]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - sv_main.c
5f2a6911c447f9c40a8c7dd24ba206a4ab1b8b00
[xonotic/darkplaces.git] / sv_main.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // sv_main.c -- server main program
21
22 #include "quakedef.h"
23 #include "libcurl.h"
24
25 void SV_VM_Init();
26 void SV_VM_Setup();
27
28 void VM_AutoSentStats_Clear (void);
29 void EntityFrameCSQC_ClearVersions (void);
30 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
31 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
32 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
33
34
35 // select which protocol to host, this is fed to Protocol_EnumForName
36 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
37 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)"};
38 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
39 cvar_t sv_allowdownloads = {0, "sv_allowdownloads", "1", "whether to allow clients to download files from the server (does not affect http downloads)"};
40 cvar_t sv_allowdownloads_inarchive = {0, "sv_allowdownloads_inarchive", "0", "whether to allow downloads from archives (pak/pk3)"};
41 cvar_t sv_allowdownloads_archive = {0, "sv_allowdownloads_archive", "0", "whether to allow downloads of archives (pak/pk3)"};
42
43 extern cvar_t sv_random_seed;
44
45 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
46 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
47 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
48 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)"};
49
50 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
51 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"};
52 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)"};
53 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)"};
54 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"};
55 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"};
56 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"};
57 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"};
58 cvar_t sv_gameplayfix_qwplayerphysics = {0, "sv_gameplayfix_qwplayerphysics", "1", "changes water jumping to make it easier to get out of water, and prevents friction on landing when bunnyhopping"};
59 cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
60 cvar_t sv_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
61
62 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
63
64 // TODO: move these cvars here
65 extern cvar_t sv_clmovement_enable;
66 extern cvar_t sv_clmovement_minping;
67 extern cvar_t sv_clmovement_minping_disabletime;
68 extern cvar_t sv_clmovement_waitforinput;
69
70 server_t sv;
71 server_static_t svs;
72
73 mempool_t *sv_mempool = NULL;
74
75 //============================================================================
76
77 extern void SV_Phys_Init (void);
78 extern void SV_World_Init (void);
79 static void SV_SaveEntFile_f(void);
80 static void SV_StartDownload_f(void);
81 static void SV_Download_f(void);
82
83 /*
84 ===============
85 SV_Init
86 ===============
87 */
88 void SV_Init (void)
89 {
90         // init the csqc progs cvars, since they are updated/used by the server code
91         // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
92         extern cvar_t csqc_progname;    //[515]: csqc crc check and right csprogs name according to progs.dat
93         extern cvar_t csqc_progcrc;
94         Cvar_RegisterVariable (&csqc_progname);
95         Cvar_RegisterVariable (&csqc_progcrc);
96
97         Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
98         Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
99         Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server");
100         Cvar_RegisterVariable (&sv_maxvelocity);
101         Cvar_RegisterVariable (&sv_gravity);
102         Cvar_RegisterVariable (&sv_friction);
103         Cvar_RegisterVariable (&sv_waterfriction);
104         Cvar_RegisterVariable (&sv_edgefriction);
105         Cvar_RegisterVariable (&sv_stopspeed);
106         Cvar_RegisterVariable (&sv_maxspeed);
107         Cvar_RegisterVariable (&sv_maxairspeed);
108         Cvar_RegisterVariable (&sv_accelerate);
109         Cvar_RegisterVariable (&sv_airaccelerate);
110         Cvar_RegisterVariable (&sv_wateraccelerate);
111         Cvar_RegisterVariable (&sv_clmovement_enable);
112         Cvar_RegisterVariable (&sv_clmovement_minping);
113         Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
114         Cvar_RegisterVariable (&sv_clmovement_waitforinput);
115         Cvar_RegisterVariable (&sv_idealpitchscale);
116         Cvar_RegisterVariable (&sv_aim);
117         Cvar_RegisterVariable (&sv_nostep);
118         Cvar_RegisterVariable (&sv_cullentities_pvs);
119         Cvar_RegisterVariable (&sv_cullentities_trace);
120         Cvar_RegisterVariable (&sv_cullentities_stats);
121         Cvar_RegisterVariable (&sv_entpatch);
122         Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
123         Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
124         Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
125         Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
126         Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
127         Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
128         Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
129         Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
130         Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
131         Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
132         Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
133         Cvar_RegisterVariable (&sv_protocolname);
134         Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
135         Cvar_RegisterVariable (&sv_maxrate);
136         Cvar_RegisterVariable (&sv_allowdownloads);
137         Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
138         Cvar_RegisterVariable (&sv_allowdownloads_archive);
139         Cvar_RegisterVariable (&sv_progs);
140
141         SV_VM_Init();
142         SV_Phys_Init();
143         SV_World_Init();
144
145         sv_mempool = Mem_AllocPool("server", 0, NULL);
146 }
147
148 static void SV_SaveEntFile_f(void)
149 {
150         char basename[MAX_QPATH];
151         if (!sv.active || !sv.worldmodel)
152         {
153                 Con_Print("Not running a server\n");
154                 return;
155         }
156         FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
157         FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
158 }
159
160
161 /*
162 =============================================================================
163
164 EVENT MESSAGES
165
166 =============================================================================
167 */
168
169 /*
170 ==================
171 SV_StartParticle
172
173 Make sure the event gets sent to all clients
174 ==================
175 */
176 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
177 {
178         int i;
179
180         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
181                 return;
182         MSG_WriteByte (&sv.datagram, svc_particle);
183         MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
184         MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
185         MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
186         for (i=0 ; i<3 ; i++)
187                 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
188         MSG_WriteByte (&sv.datagram, count);
189         MSG_WriteByte (&sv.datagram, color);
190 }
191
192 /*
193 ==================
194 SV_StartEffect
195
196 Make sure the event gets sent to all clients
197 ==================
198 */
199 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
200 {
201         if (modelindex >= 256 || startframe >= 256)
202         {
203                 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
204                         return;
205                 MSG_WriteByte (&sv.datagram, svc_effect2);
206                 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
207                 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
208                 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
209                 MSG_WriteShort (&sv.datagram, modelindex);
210                 MSG_WriteShort (&sv.datagram, startframe);
211                 MSG_WriteByte (&sv.datagram, framecount);
212                 MSG_WriteByte (&sv.datagram, framerate);
213         }
214         else
215         {
216                 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
217                         return;
218                 MSG_WriteByte (&sv.datagram, svc_effect);
219                 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
220                 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
221                 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
222                 MSG_WriteByte (&sv.datagram, modelindex);
223                 MSG_WriteByte (&sv.datagram, startframe);
224                 MSG_WriteByte (&sv.datagram, framecount);
225                 MSG_WriteByte (&sv.datagram, framerate);
226         }
227 }
228
229 /*
230 ==================
231 SV_StartSound
232
233 Each entity can have eight independant sound sources, like voice,
234 weapon, feet, etc.
235
236 Channel 0 is an auto-allocate channel, the others override anything
237 already running on that entity/channel pair.
238
239 An attenuation of 0 will play full volume everywhere in the level.
240 Larger attenuations will drop off.  (max 4 attenuation)
241
242 ==================
243 */
244 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
245 {
246         int sound_num, field_mask, i, ent;
247
248         if (volume < 0 || volume > 255)
249         {
250                 Con_Printf ("SV_StartSound: volume = %i\n", volume);
251                 return;
252         }
253
254         if (attenuation < 0 || attenuation > 4)
255         {
256                 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
257                 return;
258         }
259
260         if (channel < 0 || channel > 7)
261         {
262                 Con_Printf ("SV_StartSound: channel = %i\n", channel);
263                 return;
264         }
265
266         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
267                 return;
268
269 // find precache number for sound
270         sound_num = SV_SoundIndex(sample, 1);
271         if (!sound_num)
272                 return;
273
274         ent = PRVM_NUM_FOR_EDICT(entity);
275
276         field_mask = 0;
277         if (volume != DEFAULT_SOUND_PACKET_VOLUME)
278                 field_mask |= SND_VOLUME;
279         if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
280                 field_mask |= SND_ATTENUATION;
281         if (ent >= 8192)
282                 field_mask |= SND_LARGEENTITY;
283         if (sound_num >= 256 || channel >= 8)
284                 field_mask |= SND_LARGESOUND;
285
286 // directed messages go only to the entity they are targeted on
287         MSG_WriteByte (&sv.datagram, svc_sound);
288         MSG_WriteByte (&sv.datagram, field_mask);
289         if (field_mask & SND_VOLUME)
290                 MSG_WriteByte (&sv.datagram, volume);
291         if (field_mask & SND_ATTENUATION)
292                 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
293         if (field_mask & SND_LARGEENTITY)
294         {
295                 MSG_WriteShort (&sv.datagram, ent);
296                 MSG_WriteByte (&sv.datagram, channel);
297         }
298         else
299                 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
300         if (field_mask & SND_LARGESOUND)
301                 MSG_WriteShort (&sv.datagram, sound_num);
302         else
303                 MSG_WriteByte (&sv.datagram, sound_num);
304         for (i = 0;i < 3;i++)
305                 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
306 }
307
308 /*
309 ==============================================================================
310
311 CLIENT SPAWNING
312
313 ==============================================================================
314 */
315
316 /*
317 ================
318 SV_SendServerinfo
319
320 Sends the first message from the server to a connected client.
321 This will be sent on the initial connection and upon each server load.
322 ================
323 */
324 void SV_SendServerinfo (client_t *client)
325 {
326         int i;
327         char message[128];
328
329         // we know that this client has a netconnection and thus is not a bot
330
331         // edicts get reallocated on level changes, so we need to update it here
332         client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
333
334         // clear cached stuff that depends on the level
335         client->weaponmodel[0] = 0;
336         client->weaponmodelindex = 0;
337
338         // LordHavoc: clear entityframe tracking
339         client->latestframenum = 0;
340
341         if (client->entitydatabase)
342                 EntityFrame_FreeDatabase(client->entitydatabase);
343         if (client->entitydatabase4)
344                 EntityFrame4_FreeDatabase(client->entitydatabase4);
345         if (client->entitydatabase5)
346                 EntityFrame5_FreeDatabase(client->entitydatabase5);
347
348         if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
349         {
350                 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
351                         client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
352                 else if (sv.protocol == PROTOCOL_DARKPLACES4)
353                         client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
354                 else
355                         client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
356         }
357
358         SZ_Clear (&client->netconnection->message);
359         MSG_WriteByte (&client->netconnection->message, svc_print);
360         dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
361         MSG_WriteString (&client->netconnection->message,message);
362
363         //[515]: init csprogs according to version of svprogs, check the crc, etc.
364         if (sv.csqc_progcrc >= 0)
365         {
366                 prvm_eval_t *val;
367                 Con_DPrintf("sending csqc info to client (\"%s\" with crc %i)\n", sv.csqc_progname, sv.csqc_progcrc);
368                 //[515]: init stufftext string (it is sent before svc_serverinfo)
369                 val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
370                 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
371                 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
372                 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
373                 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
374                 if (val)
375                 {
376                         MSG_WriteByte (&client->netconnection->message, svc_stufftext);
377                         MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
378                 }
379         }
380
381         if (sv_allowdownloads.integer)
382         {
383                 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
384                 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
385         }
386
387         MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
388         MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
389         MSG_WriteByte (&client->netconnection->message, svs.maxclients);
390
391         if (!coop.integer && deathmatch.integer)
392                 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
393         else
394                 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
395
396         MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
397
398         for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
399                 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
400         MSG_WriteByte (&client->netconnection->message, 0);
401
402         for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
403                 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
404         MSG_WriteByte (&client->netconnection->message, 0);
405
406 // send music
407         MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
408         MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
409         MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
410
411 // set view
412         MSG_WriteByte (&client->netconnection->message, svc_setview);
413         MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
414
415         MSG_WriteByte (&client->netconnection->message, svc_signonnum);
416         MSG_WriteByte (&client->netconnection->message, 1);
417
418         {
419                 client_t *save;
420                 save = host_client;
421                 host_client = client;
422                 Curl_SendRequirements();
423                 host_client = save;
424         }
425
426         client->spawned = false;                // need prespawn, spawn, etc
427 }
428
429 /*
430 ================
431 SV_ConnectClient
432
433 Initializes a client_t for a new net connection.  This will only be called
434 once for a player each game, not once for each level change.
435 ================
436 */
437 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
438 {
439         client_t                *client;
440         int                             i;
441         float                   spawn_parms[NUM_SPAWN_PARMS];
442
443         client = svs.clients + clientnum;
444
445         if(netconnection)//[515]: bots don't play with csqc =)
446                 EntityFrameCSQC_InitClientVersions(clientnum, false);
447
448 // set up the client_t
449         if (sv.loadgame)
450                 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
451         memset (client, 0, sizeof(*client));
452         client->active = true;
453         client->netconnection = netconnection;
454
455         Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
456
457         strlcpy(client->name, "unconnected", sizeof(client->name));
458         strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
459         client->spawned = false;
460         client->edict = PRVM_EDICT_NUM(clientnum+1);
461         if (client->netconnection)
462                 client->netconnection->message.allowoverflow = true;            // we can catch it
463         // updated by receiving "rate" command from client
464         client->rate = NET_MINRATE;
465         // no limits for local player
466         if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
467                 client->rate = 1000000000;
468         client->connecttime = realtime;
469
470         if (sv.loadgame)
471                 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
472         else
473         {
474                 // call the progs to get default spawn parms for the new client
475                 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
476                 prog->globals.server->self = 0;
477                 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
478                 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
479                         client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
480
481                 // set up the entity for this client (including .colormap, .team, etc)
482                 PRVM_ED_ClearEdict(client->edict);
483         }
484
485         // don't call SendServerinfo for a fresh botclient because its fields have
486         // not been set up by the qc yet
487         if (client->netconnection)
488                 SV_SendServerinfo (client);
489         else
490                 client->spawned = true;
491 }
492
493
494 /*
495 ===============================================================================
496
497 FRAME UPDATES
498
499 ===============================================================================
500 */
501
502 /*
503 ==================
504 SV_ClearDatagram
505
506 ==================
507 */
508 void SV_ClearDatagram (void)
509 {
510         SZ_Clear (&sv.datagram);
511 }
512
513 /*
514 =============================================================================
515
516 The PVS must include a small area around the client to allow head bobbing
517 or other small motion on the client side.  Otherwise, a bob might cause an
518 entity that should be visible to not show up, especially when the bob
519 crosses a waterline.
520
521 =============================================================================
522 */
523
524 int sv_writeentitiestoclient_pvsbytes;
525 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
526
527 static int numsendentities;
528 static entity_state_t sendentities[MAX_EDICTS];
529 static entity_state_t *sendentitiesindex[MAX_EDICTS];
530
531 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
532 {
533         int i;
534         unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
535         unsigned int customizeentityforclient;
536         float f;
537         vec3_t cullmins, cullmaxs;
538         model_t *model;
539         prvm_eval_t *val;
540
541         // EF_NODRAW prevents sending for any reason except for your own
542         // client, so we must keep all clients in this superset
543         effects = (unsigned)ent->fields.server->effects;
544
545         // we can omit invisible entities with no effects that are not clients
546         // LordHavoc: this could kill tags attached to an invisible entity, I
547         // just hope we never have to support that case
548         i = (int)ent->fields.server->modelindex;
549         modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
550
551         flags = 0;
552         i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
553         glowsize = (unsigned char)bound(0, i, 255);
554         if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
555                 flags |= RENDER_GLOWTRAIL;
556
557         f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
558         light[0] = (unsigned short)bound(0, f, 65535);
559         f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
560         light[1] = (unsigned short)bound(0, f, 65535);
561         f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
562         light[2] = (unsigned short)bound(0, f, 65535);
563         f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
564         light[3] = (unsigned short)bound(0, f, 65535);
565         lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
566         lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
567
568         if (gamemode == GAME_TENEBRAE)
569         {
570                 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
571                 if (effects & 16)
572                 {
573                         effects &= ~16;
574                         lightpflags |= PFLAGS_FULLDYNAMIC;
575                 }
576                 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
577                 if (effects & 32)
578                 {
579                         effects &= ~32;
580                         light[0] = (int)(0.2*256);
581                         light[1] = (int)(1.0*256);
582                         light[2] = (int)(0.2*256);
583                         light[3] = 200;
584                         lightpflags |= PFLAGS_FULLDYNAMIC;
585                 }
586         }
587
588         specialvisibilityradius = 0;
589         if (lightpflags & PFLAGS_FULLDYNAMIC)
590                 specialvisibilityradius = max(specialvisibilityradius, light[3]);
591         if (glowsize)
592                 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
593         if (flags & RENDER_GLOWTRAIL)
594                 specialvisibilityradius = max(specialvisibilityradius, 100);
595         if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
596         {
597                 if (effects & EF_BRIGHTFIELD)
598                         specialvisibilityradius = max(specialvisibilityradius, 80);
599                 if (effects & EF_MUZZLEFLASH)
600                         specialvisibilityradius = max(specialvisibilityradius, 100);
601                 if (effects & EF_BRIGHTLIGHT)
602                         specialvisibilityradius = max(specialvisibilityradius, 400);
603                 if (effects & EF_DIMLIGHT)
604                         specialvisibilityradius = max(specialvisibilityradius, 200);
605                 if (effects & EF_RED)
606                         specialvisibilityradius = max(specialvisibilityradius, 200);
607                 if (effects & EF_BLUE)
608                         specialvisibilityradius = max(specialvisibilityradius, 200);
609                 if (effects & EF_FLAME)
610                         specialvisibilityradius = max(specialvisibilityradius, 250);
611                 if (effects & EF_STARDUST)
612                         specialvisibilityradius = max(specialvisibilityradius, 100);
613         }
614
615         // early culling checks
616         // (final culling is done by SV_MarkWriteEntityStateToClient)
617         customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
618         if (!customizeentityforclient)
619         {
620                 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
621                         return false;
622                 // this 2 billion unit check is actually to detect NAN origins
623                 // (we really don't want to send those)
624                 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
625                         return false;
626         }
627
628
629         *cs = defaultstate;
630         cs->active = true;
631         cs->number = e;
632         VectorCopy(ent->fields.server->origin, cs->origin);
633         VectorCopy(ent->fields.server->angles, cs->angles);
634         cs->flags = flags;
635         cs->effects = effects;
636         cs->colormap = (unsigned)ent->fields.server->colormap;
637         cs->modelindex = modelindex;
638         cs->skin = (unsigned)ent->fields.server->skin;
639         cs->frame = (unsigned)ent->fields.server->frame;
640         cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
641         cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
642         cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
643         cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
644         cs->customizeentityforclient = customizeentityforclient;
645         cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
646         cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
647         cs->glowsize = glowsize;
648
649         // don't need to init cs->colormod because the defaultstate did that for us
650         //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
651         val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
652         if (val->vector[0] || val->vector[1] || val->vector[2])
653         {
654                 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
655                 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
656                 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
657         }
658
659         cs->modelindex = modelindex;
660
661         cs->alpha = 255;
662         f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
663         if (f)
664         {
665                 i = (int)f;
666                 cs->alpha = (unsigned char)bound(0, i, 255);
667         }
668         // halflife
669         f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
670         if (f)
671         {
672                 i = (int)f;
673                 cs->alpha = (unsigned char)bound(0, i, 255);
674         }
675
676         cs->scale = 16;
677         f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
678         if (f)
679         {
680                 i = (int)f;
681                 cs->scale = (unsigned char)bound(0, i, 255);
682         }
683
684         cs->glowcolor = 254;
685         f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
686         if (f)
687                 cs->glowcolor = (int)f;
688
689         if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
690                 cs->effects |= EF_FULLBRIGHT;
691
692         if (ent->fields.server->movetype == MOVETYPE_STEP)
693                 cs->flags |= RENDER_STEP;
694         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)
695                 cs->flags |= RENDER_LOWPRECISION;
696         if (ent->fields.server->colormap >= 1024)
697                 cs->flags |= RENDER_COLORMAPPED;
698         if (cs->viewmodelforclient)
699                 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
700
701         cs->light[0] = light[0];
702         cs->light[1] = light[1];
703         cs->light[2] = light[2];
704         cs->light[3] = light[3];
705         cs->lightstyle = lightstyle;
706         cs->lightpflags = lightpflags;
707
708         cs->specialvisibilityradius = specialvisibilityradius;
709
710         // calculate the visible box of this entity (don't use the physics box
711         // as that is often smaller than a model, and would not count
712         // specialvisibilityradius)
713         if ((model = sv.models[modelindex]))
714         {
715                 float scale = cs->scale * (1.0f / 16.0f);
716                 if (cs->angles[0] || cs->angles[2]) // pitch and roll
717                 {
718                         VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
719                         VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
720                 }
721                 else if (cs->angles[1])
722                 {
723                         VectorMA(cs->origin, scale, model->yawmins, cullmins);
724                         VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
725                 }
726                 else
727                 {
728                         VectorMA(cs->origin, scale, model->normalmins, cullmins);
729                         VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
730                 }
731         }
732         else
733         {
734                 // if there is no model (or it could not be loaded), use the physics box
735                 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
736                 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
737         }
738         if (specialvisibilityradius)
739         {
740                 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
741                 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
742                 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
743                 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
744                 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
745                 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
746         }
747         if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
748         {
749                 VectorCopy(cullmins, ent->priv.server->cullmins);
750                 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
751                 ent->priv.server->pvs_numclusters = -1;
752                 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
753                 {
754                         i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
755                         if (i <= MAX_ENTITYCLUSTERS)
756                                 ent->priv.server->pvs_numclusters = i;
757                 }
758         }
759
760         return true;
761 }
762
763 void SV_PrepareEntitiesForSending(void)
764 {
765         int e;
766         prvm_edict_t *ent;
767         // send all entities that touch the pvs
768         numsendentities = 0;
769         sendentitiesindex[0] = NULL;
770         memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
771         for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
772         {
773                 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
774                 {
775                         sendentitiesindex[e] = sendentities + numsendentities;
776                         numsendentities++;
777                 }
778         }
779 }
780
781 static int sententitiesmark = 0;
782 static int sententities[MAX_EDICTS];
783 static int sententitiesconsideration[MAX_EDICTS];
784 static int sv_writeentitiestoclient_culled_pvs;
785 static int sv_writeentitiestoclient_culled_trace;
786 static int sv_writeentitiestoclient_visibleentities;
787 static int sv_writeentitiestoclient_totalentities;
788 //static entity_frame_t sv_writeentitiestoclient_entityframe;
789 static int sv_writeentitiestoclient_clentnum;
790 static vec3_t sv_writeentitiestoclient_testeye;
791 static client_t *sv_writeentitiestoclient_client;
792
793 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
794 {
795         int isbmodel;
796         vec3_t testorigin;
797         model_t *model;
798         prvm_edict_t *ed;
799         trace_t trace;
800         if (sententitiesconsideration[s->number] == sententitiesmark)
801                 return;
802         sententitiesconsideration[s->number] = sententitiesmark;
803         sv_writeentitiestoclient_totalentities++;
804
805         if (s->customizeentityforclient)
806         {
807                 prog->globals.server->self = s->number;
808                 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
809                 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
810                 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
811                         return;
812         }
813
814         // never reject player
815         if (s->number != sv_writeentitiestoclient_clentnum)
816         {
817                 // check various rejection conditions
818                 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
819                         return;
820                 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
821                         return;
822                 if (s->effects & EF_NODRAW)
823                         return;
824                 // LordHavoc: only send entities with a model or important effects
825                 if (!s->modelindex && s->specialvisibilityradius == 0)
826                         return;
827
828                 // viewmodels don't have visibility checking
829                 if (s->viewmodelforclient)
830                 {
831                         if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
832                                 return;
833                 }
834                 else if (s->tagentity)
835                 {
836                         // tag attached entities simply check their parent
837                         if (!sendentitiesindex[s->tagentity])
838                                 return;
839                         SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
840                         if (sententities[s->tagentity] != sententitiesmark)
841                                 return;
842                 }
843                 // always send world submodels in newer protocols because they don't
844                 // generate much traffic (in old protocols they hog bandwidth)
845                 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)))
846                 {
847                         // entity has survived every check so far, check if visible
848                         ed = PRVM_EDICT_NUM(s->number);
849
850                         // if not touching a visible leaf
851                         if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
852                         {
853                                 if (ed->priv.server->pvs_numclusters < 0)
854                                 {
855                                         // entity too big for clusters list
856                                         if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
857                                         {
858                                                 sv_writeentitiestoclient_culled_pvs++;
859                                                 return;
860                                         }
861                                 }
862                                 else
863                                 {
864                                         int i;
865                                         // check cached clusters list
866                                         for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
867                                                 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
868                                                         break;
869                                         if (i == ed->priv.server->pvs_numclusters)
870                                         {
871                                                 sv_writeentitiestoclient_culled_pvs++;
872                                                 return;
873                                         }
874                                 }
875                         }
876
877                         // or not seen by random tracelines
878                         if (sv_cullentities_trace.integer && !isbmodel)
879                         {
880                                 // LordHavoc: test center first
881                                 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
882                                 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
883                                 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
884                                 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
885                                 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
886                                         sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
887                                 else
888                                 {
889                                         // LordHavoc: test random offsets, to maximize chance of detection
890                                         testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
891                                         testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
892                                         testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
893                                         sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
894                                         if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
895                                                 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
896                                         else
897                                         {
898                                                 if (s->specialvisibilityradius)
899                                                 {
900                                                         // LordHavoc: test random offsets, to maximize chance of detection
901                                                         testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
902                                                         testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
903                                                         testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
904                                                         sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
905                                                         if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
906                                                                 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
907                                                 }
908                                         }
909                                 }
910                                 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
911                                 {
912                                         sv_writeentitiestoclient_culled_trace++;
913                                         return;
914                                 }
915                         }
916                 }
917         }
918
919         // this just marks it for sending
920         // FIXME: it would be more efficient to send here, but the entity
921         // compressor isn't that flexible
922         sv_writeentitiestoclient_visibleentities++;
923         sententities[s->number] = sententitiesmark;
924 }
925
926 entity_state_t sendstates[MAX_EDICTS];
927 extern int csqc_clent;
928
929 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
930 {
931         int i, numsendstates;
932         entity_state_t *s;
933
934         // if there isn't enough space to accomplish anything, skip it
935         if (msg->cursize + 25 > msg->maxsize)
936                 return;
937
938         sv_writeentitiestoclient_client = client;
939
940         sv_writeentitiestoclient_culled_pvs = 0;
941         sv_writeentitiestoclient_culled_trace = 0;
942         sv_writeentitiestoclient_visibleentities = 0;
943         sv_writeentitiestoclient_totalentities = 0;
944
945 // find the client's PVS
946         // the real place being tested from
947         VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
948         sv_writeentitiestoclient_pvsbytes = 0;
949         if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
950                 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
951
952         csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
953
954         sententitiesmark++;
955
956         for (i = 0;i < numsendentities;i++)
957                 SV_MarkWriteEntityStateToClient(sendentities + i);
958
959         numsendstates = 0;
960         for (i = 0;i < numsendentities;i++)
961         {
962                 if (sententities[sendentities[i].number] == sententitiesmark)
963                 {
964                         s = &sendstates[numsendstates++];
965                         *s = sendentities[i];
966                         if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
967                                 s->flags |= RENDER_EXTERIORMODEL;
968                 }
969         }
970
971         if (sv_cullentities_stats.integer)
972                 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);
973
974         EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
975
976         if (client->entitydatabase5)
977                 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
978         else if (client->entitydatabase4)
979                 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
980         else if (client->entitydatabase)
981                 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
982         else
983                 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
984 }
985
986 /*
987 =============
988 SV_CleanupEnts
989
990 =============
991 */
992 void SV_CleanupEnts (void)
993 {
994         int             e;
995         prvm_edict_t    *ent;
996
997         ent = PRVM_NEXT_EDICT(prog->edicts);
998         for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
999                 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1000 }
1001
1002 /*
1003 ==================
1004 SV_WriteClientdataToMessage
1005
1006 ==================
1007 */
1008 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1009 {
1010         int             bits;
1011         int             i;
1012         prvm_edict_t    *other;
1013         int             items;
1014         prvm_eval_t     *val;
1015         vec3_t  punchvector;
1016         int             viewzoom;
1017         const char *s;
1018
1019 //
1020 // send a damage message
1021 //
1022         if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1023         {
1024                 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1025                 MSG_WriteByte (msg, svc_damage);
1026                 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1027                 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1028                 for (i=0 ; i<3 ; i++)
1029                         MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1030
1031                 ent->fields.server->dmg_take = 0;
1032                 ent->fields.server->dmg_save = 0;
1033         }
1034
1035 //
1036 // send the current viewpos offset from the view entity
1037 //
1038         SV_SetIdealPitch ();            // how much to look up / down ideally
1039
1040 // a fixangle might get lost in a dropped packet.  Oh well.
1041         if ( ent->fields.server->fixangle )
1042         {
1043                 MSG_WriteByte (msg, svc_setangle);
1044                 for (i=0 ; i < 3 ; i++)
1045                         MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1046                 ent->fields.server->fixangle = 0;
1047         }
1048
1049         // stuff the sigil bits into the high bits of items for sbar, or else
1050         // mix in items2
1051         val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1052         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1053                 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1054         else
1055                 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1056
1057         VectorClear(punchvector);
1058         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1059                 VectorCopy(val->vector, punchvector);
1060
1061         // cache weapon model name and index in client struct to save time
1062         // (this search can be almost 1% of cpu time!)
1063         s = PRVM_GetString(ent->fields.server->weaponmodel);
1064         if (strcmp(s, client->weaponmodel))
1065         {
1066                 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1067                 client->weaponmodelindex = SV_ModelIndex(s, 1);
1068         }
1069
1070         viewzoom = 255;
1071         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1072                 viewzoom = (int)(val->_float * 255.0f);
1073         if (viewzoom == 0)
1074                 viewzoom = 255;
1075
1076         bits = 0;
1077
1078         if ((int)ent->fields.server->flags & FL_ONGROUND)
1079                 bits |= SU_ONGROUND;
1080         if (ent->fields.server->waterlevel >= 2)
1081                 bits |= SU_INWATER;
1082         if (ent->fields.server->idealpitch)
1083                 bits |= SU_IDEALPITCH;
1084
1085         for (i=0 ; i<3 ; i++)
1086         {
1087                 if (ent->fields.server->punchangle[i])
1088                         bits |= (SU_PUNCH1<<i);
1089                 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1090                         if (punchvector[i])
1091                                 bits |= (SU_PUNCHVEC1<<i);
1092                 if (ent->fields.server->velocity[i])
1093                         bits |= (SU_VELOCITY1<<i);
1094         }
1095
1096         memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1097         stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1098         stats[STAT_ITEMS] = items;
1099         stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1100         stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1101         stats[STAT_WEAPON] = client->weaponmodelindex;
1102         stats[STAT_HEALTH] = (int)ent->fields.server->health;
1103         stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1104         stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1105         stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1106         stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1107         stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1108         stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1109         stats[STAT_VIEWZOOM] = viewzoom;
1110         stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1111         stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1112         // the QC bumps these itself by sending svc_'s, so we have to keep them
1113         // zero or they'll be corrected by the engine
1114         //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1115         //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1116
1117         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)
1118         {
1119                 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1120                 bits |= SU_ITEMS;
1121                 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1122                 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1123                 bits |= SU_WEAPON;
1124                 // FIXME: which protocols support this?  does PROTOCOL_DARKPLACES3 support viewzoom?
1125                 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1126                         if (viewzoom != 255)
1127                                 bits |= SU_VIEWZOOM;
1128         }
1129
1130         if (bits >= 65536)
1131                 bits |= SU_EXTEND1;
1132         if (bits >= 16777216)
1133                 bits |= SU_EXTEND2;
1134
1135         // send the data
1136         MSG_WriteByte (msg, svc_clientdata);
1137         MSG_WriteShort (msg, bits);
1138         if (bits & SU_EXTEND1)
1139                 MSG_WriteByte(msg, bits >> 16);
1140         if (bits & SU_EXTEND2)
1141                 MSG_WriteByte(msg, bits >> 24);
1142
1143         if (bits & SU_VIEWHEIGHT)
1144                 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1145
1146         if (bits & SU_IDEALPITCH)
1147                 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1148
1149         for (i=0 ; i<3 ; i++)
1150         {
1151                 if (bits & (SU_PUNCH1<<i))
1152                 {
1153                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1154                                 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1155                         else
1156                                 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1157                 }
1158                 if (bits & (SU_PUNCHVEC1<<i))
1159                 {
1160                         if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1161                                 MSG_WriteCoord16i(msg, punchvector[i]);
1162                         else
1163                                 MSG_WriteCoord32f(msg, punchvector[i]);
1164                 }
1165                 if (bits & (SU_VELOCITY1<<i))
1166                 {
1167                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1168                                 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1169                         else
1170                                 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1171                 }
1172         }
1173
1174         if (bits & SU_ITEMS)
1175                 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1176
1177         if (sv.protocol == PROTOCOL_DARKPLACES5)
1178         {
1179                 if (bits & SU_WEAPONFRAME)
1180                         MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1181                 if (bits & SU_ARMOR)
1182                         MSG_WriteShort (msg, stats[STAT_ARMOR]);
1183                 if (bits & SU_WEAPON)
1184                         MSG_WriteShort (msg, stats[STAT_WEAPON]);
1185                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1186                 MSG_WriteShort (msg, stats[STAT_AMMO]);
1187                 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1188                 MSG_WriteShort (msg, stats[STAT_NAILS]);
1189                 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1190                 MSG_WriteShort (msg, stats[STAT_CELLS]);
1191                 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1192                 if (bits & SU_VIEWZOOM)
1193                         MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1194         }
1195         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)
1196         {
1197                 if (bits & SU_WEAPONFRAME)
1198                         MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1199                 if (bits & SU_ARMOR)
1200                         MSG_WriteByte (msg, stats[STAT_ARMOR]);
1201                 if (bits & SU_WEAPON)
1202                         MSG_WriteByte (msg, stats[STAT_WEAPON]);
1203                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1204                 MSG_WriteByte (msg, stats[STAT_AMMO]);
1205                 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1206                 MSG_WriteByte (msg, stats[STAT_NAILS]);
1207                 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1208                 MSG_WriteByte (msg, stats[STAT_CELLS]);
1209                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1210                 {
1211                         for (i = 0;i < 32;i++)
1212                                 if (stats[STAT_WEAPON] & (1<<i))
1213                                         break;
1214                         MSG_WriteByte (msg, i);
1215                 }
1216                 else
1217                         MSG_WriteByte (msg, stats[STAT_WEAPON]);
1218                 if (bits & SU_VIEWZOOM)
1219                 {
1220                         if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1221                                 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1222                         else
1223                                 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1224                 }
1225         }
1226 }
1227
1228 /*
1229 =======================
1230 SV_SendClientDatagram
1231 =======================
1232 */
1233 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1234 void SV_SendClientDatagram (client_t *client)
1235 {
1236         int rate, maxrate, maxsize, maxsize2, downloadsize;
1237         sizebuf_t msg;
1238         int stats[MAX_CL_STATS];
1239
1240         if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1241         {
1242                 // for good singleplayer, send huge packets
1243                 maxsize = sizeof(sv_sendclientdatagram_buf);
1244                 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1245         }
1246         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)
1247         {
1248                 // no rate limiting support on older protocols because dp protocols
1249                 // 1-4 kick the client off if they overflow, and quake protocol shows
1250                 // less than the full entity set if rate limited
1251                 maxsize = 1400;
1252                 maxsize2 = 1400;
1253         }
1254         else
1255         {
1256                 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1257                 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1258                 if (sv_maxrate.integer != maxrate)
1259                         Cvar_SetValueQuick(&sv_maxrate, maxrate);
1260
1261                 // this rate limiting does not understand sys_ticrate 0
1262                 // (but no one should be running that on a server!)
1263                 rate = bound(NET_MINRATE, client->rate, maxrate);
1264                 rate = (int)(rate * sys_ticrate.value);
1265                 maxsize = bound(100, rate, 1400);
1266                 maxsize2 = 1400;
1267         }
1268
1269         // while downloading, limit entity updates to half the packet
1270         // (any leftover space will be used for downloading)
1271         if (host_client->download_file)
1272                 maxsize /= 2;
1273
1274         msg.data = sv_sendclientdatagram_buf;
1275         msg.maxsize = maxsize;
1276         msg.cursize = 0;
1277
1278         if (host_client->spawned)
1279         {
1280                 MSG_WriteByte (&msg, svc_time);
1281                 MSG_WriteFloat (&msg, sv.time);
1282
1283                 // add the client specific data to the datagram
1284                 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1285                 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1286                 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1287
1288                 // expand packet size to allow effects to go over the rate limit
1289                 // (dropping them is FAR too ugly)
1290                 msg.maxsize = maxsize2;
1291
1292                 // copy the server datagram if there is space
1293                 // FIXME: put in delayed queue of effects to send
1294                 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1295                         SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1296         }
1297         else if (realtime > client->keepalivetime)
1298         {
1299                 // the player isn't totally in the game yet
1300                 // send small keepalive messages if too much time has passed
1301                 msg.maxsize = maxsize2;
1302                 client->keepalivetime = realtime + 5;
1303                 MSG_WriteChar (&msg, svc_nop);
1304         }
1305
1306         msg.maxsize = maxsize2;
1307
1308         // if a download is active, see if there is room to fit some download data
1309         // in this packet
1310         downloadsize = maxsize * 2 - msg.cursize - 7;
1311         if (host_client->download_file && host_client->download_started && downloadsize > 0)
1312         {
1313                 fs_offset_t downloadstart;
1314                 unsigned char data[1400];
1315                 downloadstart = FS_Tell(host_client->download_file);
1316                 downloadsize = min(downloadsize, (int)sizeof(data));
1317                 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1318                 // note this sends empty messages if at the end of the file, which is
1319                 // necessary to keep the packet loss logic working
1320                 // (the last blocks may be lost and need to be re-sent, and that will
1321                 //  only occur if the client acks the empty end messages, revealing
1322                 //  a gap in the download progress, causing the last blocks to be
1323                 //  sent again)
1324                 MSG_WriteChar (&msg, svc_downloaddata);
1325                 MSG_WriteLong (&msg, downloadstart);
1326                 MSG_WriteShort (&msg, downloadsize);
1327                 if (downloadsize > 0)
1328                         SZ_Write (&msg, data, downloadsize);
1329         }
1330
1331 // send the datagram
1332         NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1333 }
1334
1335 /*
1336 =======================
1337 SV_UpdateToReliableMessages
1338 =======================
1339 */
1340 void SV_UpdateToReliableMessages (void)
1341 {
1342         int i, j;
1343         client_t *client;
1344         prvm_eval_t *val;
1345         const char *name;
1346         const char *model;
1347         const char *skin;
1348
1349 // check for changes to be sent over the reliable streams
1350         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1351         {
1352                 // update the host_client fields we care about according to the entity fields
1353                 host_client->edict = PRVM_EDICT_NUM(i+1);
1354
1355                 // DP_SV_CLIENTNAME
1356                 name = PRVM_GetString(host_client->edict->fields.server->netname);
1357                 if (name == NULL)
1358                         name = "";
1359                 // always point the string back at host_client->name to keep it safe
1360                 strlcpy (host_client->name, name, sizeof (host_client->name));
1361                 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1362                 if (strcmp(host_client->old_name, host_client->name))
1363                 {
1364                         if (host_client->spawned)
1365                                 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1366                         strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1367                         // send notification to all clients
1368                         MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1369                         MSG_WriteByte (&sv.reliable_datagram, i);
1370                         MSG_WriteString (&sv.reliable_datagram, host_client->name);
1371                 }
1372
1373                 // DP_SV_CLIENTCOLORS
1374                 // this is always found (since it's added by the progs loader)
1375                 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1376                         host_client->colors = (int)val->_float;
1377                 if (host_client->old_colors != host_client->colors)
1378                 {
1379                         host_client->old_colors = host_client->colors;
1380                         // send notification to all clients
1381                         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1382                         MSG_WriteByte (&sv.reliable_datagram, i);
1383                         MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1384                 }
1385
1386                 // NEXUIZ_PLAYERMODEL
1387                 if( eval_playermodel ) {
1388                         model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1389                         if (model == NULL)
1390                                 model = "";
1391                         // always point the string back at host_client->name to keep it safe
1392                         strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1393                         PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1394                 }
1395
1396                 // NEXUIZ_PLAYERSKIN
1397                 if( eval_playerskin ) {
1398                         skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1399                         if (skin == NULL)
1400                                 skin = "";
1401                         // always point the string back at host_client->name to keep it safe
1402                         strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1403                         PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1404                 }
1405
1406                 // frags
1407                 host_client->frags = (int)host_client->edict->fields.server->frags;
1408                 if (host_client->old_frags != host_client->frags)
1409                 {
1410                         host_client->old_frags = host_client->frags;
1411                         // send notification to all clients
1412                         MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1413                         MSG_WriteByte (&sv.reliable_datagram, i);
1414                         MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1415                 }
1416         }
1417
1418         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1419                 if (client->netconnection)
1420                         SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1421
1422         SZ_Clear (&sv.reliable_datagram);
1423 }
1424
1425
1426 /*
1427 =======================
1428 SV_SendClientMessages
1429 =======================
1430 */
1431 void SV_SendClientMessages (void)
1432 {
1433         int i, prepared = false;
1434
1435         if (sv.protocol == PROTOCOL_QUAKEWORLD)
1436                 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1437
1438 // update frags, names, etc
1439         SV_UpdateToReliableMessages();
1440
1441 // build individual updates
1442         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1443         {
1444                 if (!host_client->active)
1445                         continue;
1446                 if (!host_client->netconnection)
1447                         continue;
1448
1449                 if (host_client->netconnection->message.overflowed)
1450                 {
1451                         SV_DropClient (true);   // if the message couldn't send, kick off
1452                         continue;
1453                 }
1454
1455                 if (!prepared)
1456                 {
1457                         prepared = true;
1458                         // only prepare entities once per frame
1459                         SV_PrepareEntitiesForSending();
1460                 }
1461                 SV_SendClientDatagram (host_client);
1462         }
1463
1464 // clear muzzle flashes
1465         SV_CleanupEnts();
1466 }
1467
1468 void SV_StartDownload_f(void)
1469 {
1470         if (host_client->download_file)
1471                 host_client->download_started = true;
1472 }
1473
1474 void SV_Download_f(void)
1475 {
1476         const char *whichpack, *whichpack2, *extension;
1477
1478         if (Cmd_Argc() != 2)
1479         {
1480                 SV_ClientPrintf("usage: download <filename>\n");
1481                 return;
1482         }
1483
1484         if (FS_CheckNastyPath(Cmd_Argv(1), false))
1485         {
1486                 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1487                 return;
1488         }
1489
1490         if (host_client->download_file)
1491         {
1492                 // at this point we'll assume the previous download should be aborted
1493                 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1494                 Host_ClientCommands("\nstopdownload\n");
1495
1496                 // close the file and reset variables
1497                 FS_Close(host_client->download_file);
1498                 host_client->download_file = NULL;
1499                 host_client->download_name[0] = 0;
1500                 host_client->download_expectedposition = 0;
1501                 host_client->download_started = false;
1502         }
1503
1504         if (!sv_allowdownloads.integer)
1505         {
1506                 SV_ClientPrintf("Downloads are disabled on this server\n");
1507                 Host_ClientCommands("\nstopdownload\n");
1508                 return;
1509         }
1510
1511         strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1512
1513         // host_client is asking to download a specified file
1514         if (developer.integer >= 100)
1515                 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1516
1517         if (!FS_FileExists(host_client->download_name))
1518         {
1519                 SV_ClientPrintf("Download rejected: server does not have the file \"%s\"\nYou may need to separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
1520                 Host_ClientCommands("\nstopdownload\n");
1521                 return;
1522         }
1523
1524         // check if the user is trying to download part of registered Quake(r)
1525         whichpack = FS_WhichPack(host_client->download_name);
1526         whichpack2 = FS_WhichPack("gfx/pop.lmp");
1527         if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1528         {
1529                 SV_ClientPrintf("Download rejected: file \"%s\" is part of registered Quake(r)\nYou must purchase Quake(r) from id Software or a retailer to get this file\nPlease go to http://www.idsoftware.com/games/quake/quake/index.php?game_section=buy\n", host_client->download_name);
1530                 Host_ClientCommands("\nstopdownload\n");
1531                 return;
1532         }
1533
1534         // check if the server has forbidden archive downloads entirely
1535         if (!sv_allowdownloads_inarchive.integer)
1536         {
1537                 whichpack = FS_WhichPack(host_client->download_name);
1538                 if (whichpack)
1539                 {
1540                         SV_ClientPrintf("Download rejected: file \"%s\" is in an archive (\"%s\")\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name, whichpack);
1541                         Host_ClientCommands("\nstopdownload\n");
1542                         return;
1543                 }
1544         }
1545
1546         if (!sv_allowdownloads_archive.integer)
1547         {
1548                 extension = FS_FileExtension(host_client->download_name);
1549                 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1550                 {
1551                         SV_ClientPrintf("Download rejected: file \"%s\" is an archive\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
1552                         Host_ClientCommands("\nstopdownload\n");
1553                         return;
1554                 }
1555         }
1556
1557         host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1558         if (!host_client->download_file)
1559         {
1560                 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1561                 Host_ClientCommands("\nstopdownload\n");
1562                 return;
1563         }
1564
1565         if (FS_FileSize(host_client->download_file) > 1<<30)
1566         {
1567                 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1568                 Host_ClientCommands("\nstopdownload\n");
1569                 FS_Close(host_client->download_file);
1570                 host_client->download_file = NULL;
1571                 return;
1572         }
1573
1574         Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1575
1576         Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1577
1578         host_client->download_expectedposition = 0;
1579         host_client->download_started = false;
1580
1581         // the rest of the download process is handled in SV_SendClientDatagram
1582         // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1583         //
1584         // no svc_downloaddata messages will be sent until sv_startdownload is
1585         // sent by the client
1586 }
1587
1588 /*
1589 ==============================================================================
1590
1591 SERVER SPAWNING
1592
1593 ==============================================================================
1594 */
1595
1596 /*
1597 ================
1598 SV_ModelIndex
1599
1600 ================
1601 */
1602 int SV_ModelIndex(const char *s, int precachemode)
1603 {
1604         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1605         char filename[MAX_QPATH];
1606         if (!s || !*s)
1607                 return 0;
1608         // testing
1609         //if (precachemode == 2)
1610         //      return 0;
1611         strlcpy(filename, s, sizeof(filename));
1612         for (i = 2;i < limit;i++)
1613         {
1614                 if (!sv.model_precache[i][0])
1615                 {
1616                         if (precachemode)
1617                         {
1618                                 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))
1619                                 {
1620                                         Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1621                                         return 0;
1622                                 }
1623                                 if (precachemode == 1)
1624                                         Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1625                                 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1626                                 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1627                                 if (sv.state != ss_loading)
1628                                 {
1629                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1630                                         MSG_WriteShort(&sv.reliable_datagram, i);
1631                                         MSG_WriteString(&sv.reliable_datagram, filename);
1632                                 }
1633                                 return i;
1634                         }
1635                         Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1636                         return 0;
1637                 }
1638                 if (!strcmp(sv.model_precache[i], filename))
1639                         return i;
1640         }
1641         Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1642         return 0;
1643 }
1644
1645 /*
1646 ================
1647 SV_SoundIndex
1648
1649 ================
1650 */
1651 int SV_SoundIndex(const char *s, int precachemode)
1652 {
1653         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1654         char filename[MAX_QPATH];
1655         if (!s || !*s)
1656                 return 0;
1657         // testing
1658         //if (precachemode == 2)
1659         //      return 0;
1660         strlcpy(filename, s, sizeof(filename));
1661         for (i = 1;i < limit;i++)
1662         {
1663                 if (!sv.sound_precache[i][0])
1664                 {
1665                         if (precachemode)
1666                         {
1667                                 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))
1668                                 {
1669                                         Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1670                                         return 0;
1671                                 }
1672                                 if (precachemode == 1)
1673                                         Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1674                                 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1675                                 if (sv.state != ss_loading)
1676                                 {
1677                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1678                                         MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1679                                         MSG_WriteString(&sv.reliable_datagram, filename);
1680                                 }
1681                                 return i;
1682                         }
1683                         Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1684                         return 0;
1685                 }
1686                 if (!strcmp(sv.sound_precache[i], filename))
1687                         return i;
1688         }
1689         Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1690         return 0;
1691 }
1692
1693 /*
1694 ================
1695 SV_CreateBaseline
1696
1697 ================
1698 */
1699 void SV_CreateBaseline (void)
1700 {
1701         int i, entnum, large;
1702         prvm_edict_t *svent;
1703
1704         // LordHavoc: clear *all* states (note just active ones)
1705         for (entnum = 0;entnum < prog->max_edicts;entnum++)
1706         {
1707                 // get the current server version
1708                 svent = PRVM_EDICT_NUM(entnum);
1709
1710                 // LordHavoc: always clear state values, whether the entity is in use or not
1711                 svent->priv.server->baseline = defaultstate;
1712
1713                 if (svent->priv.server->free)
1714                         continue;
1715                 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1716                         continue;
1717
1718                 // create entity baseline
1719                 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1720                 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1721                 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1722                 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1723                 if (entnum > 0 && entnum <= svs.maxclients)
1724                 {
1725                         svent->priv.server->baseline.colormap = entnum;
1726                         svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1727                 }
1728                 else
1729                 {
1730                         svent->priv.server->baseline.colormap = 0;
1731                         svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1732                 }
1733
1734                 large = false;
1735                 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1736                         large = true;
1737
1738                 // add to the message
1739                 if (large)
1740                         MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1741                 else
1742                         MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1743                 MSG_WriteShort (&sv.signon, entnum);
1744
1745                 if (large)
1746                 {
1747                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1748                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1749                 }
1750                 else
1751                 {
1752                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1753                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1754                 }
1755                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1756                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1757                 for (i=0 ; i<3 ; i++)
1758                 {
1759                         MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1760                         MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1761                 }
1762         }
1763 }
1764
1765
1766 /*
1767 ================
1768 SV_SaveSpawnparms
1769
1770 Grabs the current state of each client for saving across the
1771 transition to another level
1772 ================
1773 */
1774 void SV_SaveSpawnparms (void)
1775 {
1776         int             i, j;
1777
1778         svs.serverflags = (int)prog->globals.server->serverflags;
1779
1780         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1781         {
1782                 if (!host_client->active)
1783                         continue;
1784
1785         // call the progs to get default spawn parms for the new client
1786                 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1787                 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1788                 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1789                         host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1790         }
1791 }
1792 /*
1793 void SV_IncreaseEdicts(void)
1794 {
1795         int i;
1796         prvm_edict_t *ent;
1797         int oldmax_edicts = prog->max_edicts;
1798         void *oldedictsengineprivate = prog->edictprivate;
1799         void *oldedictsfields = prog->edictsfields;
1800         void *oldmoved_edicts = sv.moved_edicts;
1801
1802         if (prog->max_edicts >= MAX_EDICTS)
1803                 return;
1804
1805         // links don't survive the transition, so unlink everything
1806         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1807         {
1808                 if (!ent->priv.server->free)
1809                         SV_UnlinkEdict(prog->edicts + i);
1810                 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1811         }
1812         SV_ClearWorld();
1813
1814         prog->max_edicts   = min(prog->max_edicts + 256, MAX_EDICTS);
1815         prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1816         prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1817         sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1818
1819         memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1820         memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1821
1822         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1823         {
1824                 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1825                 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1826                 // link every entity except world
1827                 if (!ent->priv.server->free)
1828                         SV_LinkEdict(ent, false);
1829         }
1830
1831         PR_Free(oldedictsengineprivate);
1832         PR_Free(oldedictsfields);
1833         PR_Free(oldmoved_edicts);
1834 }*/
1835
1836 /*
1837 ================
1838 SV_SpawnServer
1839
1840 This is called at the start of each level
1841 ================
1842 */
1843 extern float            scr_centertime_off;
1844
1845 void SV_SpawnServer (const char *server)
1846 {
1847         prvm_edict_t *ent;
1848         int i;
1849         char *entities;
1850         model_t *worldmodel;
1851         char modelname[sizeof(sv.modelname)];
1852
1853         Con_DPrintf("SpawnServer: %s\n", server);
1854
1855         if (cls.state != ca_dedicated)
1856                 SCR_BeginLoadingPlaque();
1857
1858         dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1859         worldmodel = Mod_ForName(modelname, false, true, true);
1860         if (!worldmodel || !worldmodel->TraceBox)
1861         {
1862                 Con_Printf("Couldn't load map %s\n", modelname);
1863                 return;
1864         }
1865
1866         // let's not have any servers with no name
1867         if (hostname.string[0] == 0)
1868                 Cvar_Set ("hostname", "UNNAMED");
1869         scr_centertime_off = 0;
1870
1871         svs.changelevel_issued = false;         // now safe to issue another
1872
1873         // make the map a required file for clients
1874         Curl_ClearRequirements();
1875         Curl_RequireFile(modelname);
1876
1877 //
1878 // tell all connected clients that we are going to a new level
1879 //
1880         if (sv.active)
1881         {
1882                 client_t *client;
1883                 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1884                 {
1885                         if (client->netconnection)
1886                         {
1887                                 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1888                                 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1889                         }
1890                 }
1891         }
1892         else
1893         {
1894                 // open server port
1895                 NetConn_OpenServerPorts(true);
1896         }
1897
1898 //
1899 // make cvars consistant
1900 //
1901         if (coop.integer)
1902                 Cvar_SetValue ("deathmatch", 0);
1903         // LordHavoc: it can be useful to have skills outside the range 0-3...
1904         //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1905         //Cvar_SetValue ("skill", (float)current_skill);
1906         current_skill = (int)(skill.value + 0.5);
1907
1908 //
1909 // set up the new server
1910 //
1911         memset (&sv, 0, sizeof(sv));
1912         // if running a local client, make sure it doesn't try to access the last
1913         // level's data which is no longer valiud
1914         cls.signon = 0;
1915
1916         if(*sv_random_seed.string)
1917         {
1918                 srand(sv_random_seed.integer);
1919                 Con_Printf("NOTE: random seed is %d; use for debugging/benchmarking only!\nUnset sv_random_seed to get real random numbers again.\n", sv_random_seed.integer);
1920         }
1921
1922         SV_VM_Setup();
1923
1924         sv.active = true;
1925
1926         strlcpy (sv.name, server, sizeof (sv.name));
1927
1928         sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1929         if (sv.protocol == PROTOCOL_UNKNOWN)
1930         {
1931                 char buffer[1024];
1932                 Protocol_Names(buffer, sizeof(buffer));
1933                 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1934                 sv.protocol = PROTOCOL_QUAKE;
1935         }
1936
1937         SV_VM_Begin();
1938
1939 // load progs to get entity field count
1940         //PR_LoadProgs ( sv_progs.string );
1941
1942         // allocate server memory
1943         /*// start out with just enough room for clients and a reasonable estimate of entities
1944         prog->max_edicts = max(svs.maxclients + 1, 512);
1945         prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1946
1947         // prvm_edict_t structures (hidden from progs)
1948         prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1949         // engine private structures (hidden from progs)
1950         prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1951         // progs fields, often accessed by server
1952         prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1953         // used by PushMove to move back pushed entities
1954         sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1955         /*for (i = 0;i < prog->max_edicts;i++)
1956         {
1957                 ent = prog->edicts + i;
1958                 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1959                 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1960         }*/
1961
1962         // reset client csqc entity versions right away.
1963         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1964                 EntityFrameCSQC_InitClientVersions(i, true);
1965
1966         sv.datagram.maxsize = sizeof(sv.datagram_buf);
1967         sv.datagram.cursize = 0;
1968         sv.datagram.data = sv.datagram_buf;
1969
1970         sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1971         sv.reliable_datagram.cursize = 0;
1972         sv.reliable_datagram.data = sv.reliable_datagram_buf;
1973
1974         sv.signon.maxsize = sizeof(sv.signon_buf);
1975         sv.signon.cursize = 0;
1976         sv.signon.data = sv.signon_buf;
1977
1978 // leave slots at start for clients only
1979         //prog->num_edicts = svs.maxclients+1;
1980
1981         sv.state = ss_loading;
1982         prog->allowworldwrites = true;
1983         sv.paused = false;
1984
1985         *prog->time = sv.time = 1.0;
1986
1987         Mod_ClearUsed();
1988         worldmodel->used = true;
1989
1990         strlcpy (sv.name, server, sizeof (sv.name));
1991         strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
1992         sv.worldmodel = worldmodel;
1993         sv.models[1] = sv.worldmodel;
1994
1995 //
1996 // clear world interaction links
1997 //
1998         SV_ClearWorld ();
1999
2000         strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2001
2002         strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2003         strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2004         for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2005         {
2006                 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2007                 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2008         }
2009
2010 //
2011 // load the rest of the entities
2012 //
2013         // AK possible hack since num_edicts is still 0
2014         ent = PRVM_EDICT_NUM(0);
2015         memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2016         ent->priv.server->free = false;
2017         ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2018         ent->fields.server->modelindex = 1;             // world model
2019         ent->fields.server->solid = SOLID_BSP;
2020         ent->fields.server->movetype = MOVETYPE_PUSH;
2021         VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2022         VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2023         VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2024         VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2025
2026         if (coop.value)
2027                 prog->globals.server->coop = coop.integer;
2028         else
2029                 prog->globals.server->deathmatch = deathmatch.integer;
2030
2031         prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2032
2033 // serverflags are for cross level information (sigils)
2034         prog->globals.server->serverflags = svs.serverflags;
2035
2036         // we need to reset the spawned flag on all connected clients here so that
2037         // their thinks don't run during startup (before PutClientInServer)
2038         // we also need to set up the client entities now
2039         // and we need to set the ->edict pointers to point into the progs edicts
2040         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2041         {
2042                 host_client->spawned = false;
2043                 host_client->edict = PRVM_EDICT_NUM(i + 1);
2044                 PRVM_ED_ClearEdict(host_client->edict);
2045         }
2046
2047         // load replacement entity file if found
2048         if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2049         {
2050                 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2051                 PRVM_ED_LoadFromFile (entities);
2052                 Mem_Free(entities);
2053         }
2054         else
2055                 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2056
2057
2058         // LordHavoc: clear world angles (to fix e3m3.bsp)
2059         VectorClear(prog->edicts->fields.server->angles);
2060
2061 // all setup is completed, any further precache statements are errors
2062         sv.state = ss_active;
2063         prog->allowworldwrites = false;
2064
2065 // run two frames to allow everything to settle
2066         for (i = 0;i < 2;i++)
2067         {
2068                 sv.frametime = 0.1;
2069                 SV_Physics ();
2070         }
2071
2072         Mod_PurgeUnused();
2073
2074 // create a baseline for more efficient communications
2075         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2076                 SV_CreateBaseline ();
2077
2078 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2079         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2080         {
2081                 if (!host_client->active)
2082                         continue;
2083                 if (host_client->netconnection)
2084                         SV_SendServerinfo(host_client);
2085                 else
2086                 {
2087                         int j;
2088                         // if client is a botclient coming from a level change, we need to
2089                         // set up client info that normally requires networking
2090
2091                         // copy spawn parms out of the client_t
2092                         for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2093                                 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2094
2095                         // call the spawn function
2096                         host_client->clientconnectcalled = true;
2097                         prog->globals.server->time = sv.time;
2098                         prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2099                         PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2100                         PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2101                         host_client->spawned = true;
2102                 }
2103         }
2104
2105         Con_DPrint("Server spawned.\n");
2106         NetConn_Heartbeat (2);
2107
2108         SV_VM_End();
2109 }
2110
2111 /////////////////////////////////////////////////////
2112 // SV VM stuff
2113
2114 void SV_VM_CB_BeginIncreaseEdicts(void)
2115 {
2116         int i;
2117         prvm_edict_t *ent;
2118
2119         PRVM_Free( sv.moved_edicts );
2120         sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2121
2122         // links don't survive the transition, so unlink everything
2123         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2124         {
2125                 if (!ent->priv.server->free)
2126                         SV_UnlinkEdict(prog->edicts + i);
2127                 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2128         }
2129         SV_ClearWorld();
2130 }
2131
2132 void SV_VM_CB_EndIncreaseEdicts(void)
2133 {
2134         int i;
2135         prvm_edict_t *ent;
2136
2137         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2138         {
2139                 // link every entity except world
2140                 if (!ent->priv.server->free)
2141                         SV_LinkEdict(ent, false);
2142         }
2143 }
2144
2145 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2146 {
2147         // LordHavoc: for consistency set these here
2148         int num = PRVM_NUM_FOR_EDICT(e) - 1;
2149
2150         e->priv.server->move = false; // don't move on first frame
2151
2152         if (num >= 0 && num < svs.maxclients)
2153         {
2154                 prvm_eval_t *val;
2155                 // set colormap and team on newly created player entity
2156                 e->fields.server->colormap = num + 1;
2157                 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2158                 // set netname/clientcolors back to client values so that
2159                 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2160                 // reset them
2161                 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2162                 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
2163                         val->_float = svs.clients[num].colors;
2164                 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2165                 if( eval_playermodel )
2166                         PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2167                 if( eval_playerskin )
2168                         PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2169         }
2170 }
2171
2172 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2173 {
2174         SV_UnlinkEdict (ed);            // unlink from world bsp
2175
2176         ed->fields.server->model = 0;
2177         ed->fields.server->takedamage = 0;
2178         ed->fields.server->modelindex = 0;
2179         ed->fields.server->colormap = 0;
2180         ed->fields.server->skin = 0;
2181         ed->fields.server->frame = 0;
2182         VectorClear(ed->fields.server->origin);
2183         VectorClear(ed->fields.server->angles);
2184         ed->fields.server->nextthink = -1;
2185         ed->fields.server->solid = 0;
2186 }
2187
2188 void SV_VM_CB_CountEdicts(void)
2189 {
2190         int             i;
2191         prvm_edict_t    *ent;
2192         int             active, models, solid, step;
2193
2194         active = models = solid = step = 0;
2195         for (i=0 ; i<prog->num_edicts ; i++)
2196         {
2197                 ent = PRVM_EDICT_NUM(i);
2198                 if (ent->priv.server->free)
2199                         continue;
2200                 active++;
2201                 if (ent->fields.server->solid)
2202                         solid++;
2203                 if (ent->fields.server->model)
2204                         models++;
2205                 if (ent->fields.server->movetype == MOVETYPE_STEP)
2206                         step++;
2207         }
2208
2209         Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2210         Con_Printf("active    :%3i\n", active);
2211         Con_Printf("view      :%3i\n", models);
2212         Con_Printf("touch     :%3i\n", solid);
2213         Con_Printf("step      :%3i\n", step);
2214 }
2215
2216 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2217 {
2218         // remove things from different skill levels or deathmatch
2219         if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2220         {
2221                 if (deathmatch.integer)
2222                 {
2223                         if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2224                         {
2225                                 return false;
2226                         }
2227                 }
2228                 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY  ))
2229                         || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2230                         || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD  )))
2231                 {
2232                         return false;
2233                 }
2234         }
2235         return true;
2236 }
2237
2238 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)"};
2239 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2240 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2241 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2242 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2243 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2244 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2245 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2246 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2247 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2248 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2249 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2250 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2251 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2252 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2253 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2254 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2255 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2256 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2257 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2258 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2259 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2260 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2261 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2262 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2263 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2264 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2265 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2266 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2267 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2268 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2269 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2270 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2271
2272 void SV_VM_Init(void)
2273 {
2274         Cvar_RegisterVariable (&pr_checkextension);
2275         Cvar_RegisterVariable (&nomonsters);
2276         Cvar_RegisterVariable (&gamecfg);
2277         Cvar_RegisterVariable (&scratch1);
2278         Cvar_RegisterVariable (&scratch2);
2279         Cvar_RegisterVariable (&scratch3);
2280         Cvar_RegisterVariable (&scratch4);
2281         Cvar_RegisterVariable (&savedgamecfg);
2282         Cvar_RegisterVariable (&saved1);
2283         Cvar_RegisterVariable (&saved2);
2284         Cvar_RegisterVariable (&saved3);
2285         Cvar_RegisterVariable (&saved4);
2286         // LordHavoc: Nehahra uses these to pass data around cutscene demos
2287         if (gamemode == GAME_NEHAHRA)
2288         {
2289                 Cvar_RegisterVariable (&nehx00);
2290                 Cvar_RegisterVariable (&nehx01);
2291                 Cvar_RegisterVariable (&nehx02);
2292                 Cvar_RegisterVariable (&nehx03);
2293                 Cvar_RegisterVariable (&nehx04);
2294                 Cvar_RegisterVariable (&nehx05);
2295                 Cvar_RegisterVariable (&nehx06);
2296                 Cvar_RegisterVariable (&nehx07);
2297                 Cvar_RegisterVariable (&nehx08);
2298                 Cvar_RegisterVariable (&nehx09);
2299                 Cvar_RegisterVariable (&nehx10);
2300                 Cvar_RegisterVariable (&nehx11);
2301                 Cvar_RegisterVariable (&nehx12);
2302                 Cvar_RegisterVariable (&nehx13);
2303                 Cvar_RegisterVariable (&nehx14);
2304                 Cvar_RegisterVariable (&nehx15);
2305                 Cvar_RegisterVariable (&nehx16);
2306                 Cvar_RegisterVariable (&nehx17);
2307                 Cvar_RegisterVariable (&nehx18);
2308                 Cvar_RegisterVariable (&nehx19);
2309         }
2310         Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2311 }
2312
2313 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue...  these are defined as externs in progs.h
2314 int eval_gravity;
2315 int eval_button3;
2316 int eval_button4;
2317 int eval_button5;
2318 int eval_button6;
2319 int eval_button7;
2320 int eval_button8;
2321 int eval_button9;
2322 int eval_button10;
2323 int eval_button11;
2324 int eval_button12;
2325 int eval_button13;
2326 int eval_button14;
2327 int eval_button15;
2328 int eval_button16;
2329 int eval_buttonuse;
2330 int eval_buttonchat;
2331 int eval_glow_size;
2332 int eval_glow_trail;
2333 int eval_glow_color;
2334 int eval_items2;
2335 int eval_scale;
2336 int eval_alpha;
2337 int eval_renderamt; // HalfLife support
2338 int eval_rendermode; // HalfLife support
2339 int eval_fullbright;
2340 int eval_ammo_shells1;
2341 int eval_ammo_nails1;
2342 int eval_ammo_lava_nails;
2343 int eval_ammo_rockets1;
2344 int eval_ammo_multi_rockets;
2345 int eval_ammo_cells1;
2346 int eval_ammo_plasma;
2347 int eval_idealpitch;
2348 int eval_pitch_speed;
2349 int eval_viewmodelforclient;
2350 int eval_nodrawtoclient;
2351 int eval_exteriormodeltoclient;
2352 int eval_drawonlytoclient;
2353 int eval_ping;
2354 int eval_movement;
2355 int eval_pmodel;
2356 int eval_punchvector;
2357 int eval_viewzoom;
2358 int eval_clientcolors;
2359 int eval_tag_entity;
2360 int eval_tag_index;
2361 int eval_light_lev;
2362 int eval_color;
2363 int eval_style;
2364 int eval_pflags;
2365 int eval_cursor_active;
2366 int eval_cursor_screen;
2367 int eval_cursor_trace_start;
2368 int eval_cursor_trace_endpos;
2369 int eval_cursor_trace_ent;
2370 int eval_colormod;
2371 int eval_playermodel;
2372 int eval_playerskin;
2373 int eval_SendEntity;
2374 int eval_Version;
2375 int eval_customizeentityforclient;
2376 int eval_dphitcontentsmask;
2377 // DRESK - Support for Entity Contents Transition Event
2378 int eval_contentstransition;
2379
2380 int gval_trace_dpstartcontents;
2381 int gval_trace_dphitcontents;
2382 int gval_trace_dphitq3surfaceflags;
2383 int gval_trace_dphittexturename;
2384
2385 mfunction_t *SV_PlayerPhysicsQC;
2386 mfunction_t *EndFrameQC;
2387 //KrimZon - SERVER COMMANDS IN QUAKEC
2388 mfunction_t *SV_ParseClientCommandQC;
2389
2390 void SV_VM_FindEdictFieldOffsets(void)
2391 {
2392         eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2393         eval_button3 = PRVM_ED_FindFieldOffset("button3");
2394         eval_button4 = PRVM_ED_FindFieldOffset("button4");
2395         eval_button5 = PRVM_ED_FindFieldOffset("button5");
2396         eval_button6 = PRVM_ED_FindFieldOffset("button6");
2397         eval_button7 = PRVM_ED_FindFieldOffset("button7");
2398         eval_button8 = PRVM_ED_FindFieldOffset("button8");
2399         eval_button9 = PRVM_ED_FindFieldOffset("button9");
2400         eval_button10 = PRVM_ED_FindFieldOffset("button10");
2401         eval_button11 = PRVM_ED_FindFieldOffset("button11");
2402         eval_button12 = PRVM_ED_FindFieldOffset("button12");
2403         eval_button13 = PRVM_ED_FindFieldOffset("button13");
2404         eval_button14 = PRVM_ED_FindFieldOffset("button14");
2405         eval_button15 = PRVM_ED_FindFieldOffset("button15");
2406         eval_button16 = PRVM_ED_FindFieldOffset("button16");
2407         eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2408         eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2409         eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2410         eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2411         eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2412         eval_items2 = PRVM_ED_FindFieldOffset("items2");
2413         eval_scale = PRVM_ED_FindFieldOffset("scale");
2414         eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2415         eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2416         eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2417         eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2418         eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2419         eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2420         eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2421         eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2422         eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2423         eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2424         eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2425         eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2426         eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2427         eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2428         eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2429         eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2430         eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2431         eval_ping = PRVM_ED_FindFieldOffset("ping");
2432         eval_movement = PRVM_ED_FindFieldOffset("movement");
2433         eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2434         eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2435         eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2436         eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2437         eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2438         eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2439         eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2440         eval_color = PRVM_ED_FindFieldOffset("color");
2441         eval_style = PRVM_ED_FindFieldOffset("style");
2442         eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2443         eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2444         eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2445         eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2446         eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2447         eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2448         eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2449         eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2450         eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2451         eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2452         eval_Version = PRVM_ED_FindFieldOffset("Version");
2453         eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2454         eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2455         // DRESK - Support for Entity Contents Transition Event
2456         eval_contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
2457
2458         // LordHavoc: allowing QuakeC to override the player movement code
2459         SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2460         // LordHavoc: support for endframe
2461         EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2462         //KrimZon - SERVER COMMANDS IN QUAKEC
2463         SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2464         gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2465         gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2466         gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2467         gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2468 }
2469
2470 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2471
2472 prvm_required_field_t reqfields[] =
2473 {
2474         {ev_entity, "cursor_trace_ent"},
2475         {ev_entity, "drawonlytoclient"},
2476         {ev_entity, "exteriormodeltoclient"},
2477         {ev_entity, "nodrawtoclient"},
2478         {ev_entity, "tag_entity"},
2479         {ev_entity, "viewmodelforclient"},
2480         {ev_float, "alpha"},
2481         {ev_float, "ammo_cells1"},
2482         {ev_float, "ammo_lava_nails"},
2483         {ev_float, "ammo_multi_rockets"},
2484         {ev_float, "ammo_nails1"},
2485         {ev_float, "ammo_plasma"},
2486         {ev_float, "ammo_rockets1"},
2487         {ev_float, "ammo_shells1"},
2488         {ev_float, "button3"},
2489         {ev_float, "button4"},
2490         {ev_float, "button5"},
2491         {ev_float, "button6"},
2492         {ev_float, "button7"},
2493         {ev_float, "button8"},
2494         {ev_float, "button9"},
2495         {ev_float, "button10"},
2496         {ev_float, "button11"},
2497         {ev_float, "button12"},
2498         {ev_float, "button13"},
2499         {ev_float, "button14"},
2500         {ev_float, "button15"},
2501         {ev_float, "button16"},
2502         {ev_float, "buttonchat"},
2503         {ev_float, "buttonuse"},
2504         {ev_float, "clientcolors"},
2505         {ev_float, "cursor_active"},
2506         {ev_float, "fullbright"},
2507         {ev_float, "glow_color"},
2508         {ev_float, "glow_size"},
2509         {ev_float, "glow_trail"},
2510         {ev_float, "gravity"},
2511         {ev_float, "idealpitch"},
2512         {ev_float, "items2"},
2513         {ev_float, "light_lev"},
2514         {ev_float, "pflags"},
2515         {ev_float, "ping"},
2516         {ev_float, "pitch_speed"},
2517         {ev_float, "pmodel"},
2518         {ev_float, "renderamt"}, // HalfLife support
2519         {ev_float, "rendermode"}, // HalfLife support
2520         {ev_float, "scale"},
2521         {ev_float, "style"},
2522         {ev_float, "tag_index"},
2523         {ev_float, "Version"},
2524         {ev_float, "viewzoom"},
2525         {ev_vector, "color"},
2526         {ev_vector, "colormod"},
2527         {ev_vector, "cursor_screen"},
2528         {ev_vector, "cursor_trace_endpos"},
2529         {ev_vector, "cursor_trace_start"},
2530         {ev_vector, "movement"},
2531         {ev_vector, "punchvector"},
2532         {ev_string, "playermodel"},
2533         {ev_string, "playerskin"},
2534         {ev_function, "SendEntity"},
2535         {ev_function, "customizeentityforclient"},
2536         // DRESK - Support for Entity Contents Transition Event
2537         {ev_function, "contentstransition"},
2538 };
2539
2540 void SV_VM_Setup(void)
2541 {
2542         extern cvar_t csqc_progname;    //[515]: csqc crc check and right csprogs name according to progs.dat
2543         extern cvar_t csqc_progcrc;
2544         unsigned char *csprogsdata;
2545         fs_offset_t csprogsdatasize;
2546         PRVM_Begin;
2547         PRVM_InitProg( PRVM_SERVERPROG );
2548
2549         // allocate the mempools
2550         // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2551         prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2552         prog->builtins = vm_sv_builtins;
2553         prog->numbuiltins = vm_sv_numbuiltins;
2554         prog->headercrc = PROGHEADER_CRC;
2555         prog->max_edicts = 512;
2556         prog->limit_edicts = MAX_EDICTS;
2557         prog->reserved_edicts = svs.maxclients;
2558         prog->edictprivate_size = sizeof(edict_engineprivate_t);
2559         prog->name = "server";
2560         prog->extensionstring = vm_sv_extensions;
2561         prog->loadintoworld = true;
2562
2563         prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2564         prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2565         prog->init_edict = SV_VM_CB_InitEdict;
2566         prog->free_edict = SV_VM_CB_FreeEdict;
2567         prog->count_edicts = SV_VM_CB_CountEdicts;
2568         prog->load_edict = SV_VM_CB_LoadEdict;
2569         prog->init_cmd = VM_SV_Cmd_Init;
2570         prog->reset_cmd = VM_SV_Cmd_Reset;
2571         prog->error_cmd = Host_Error;
2572
2573         // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2574         PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2575         SV_VM_FindEdictFieldOffsets();
2576
2577         VM_AutoSentStats_Clear();//[515]: csqc
2578         EntityFrameCSQC_ClearVersions();//[515]: csqc
2579
2580         PRVM_End;
2581
2582         // see if there is a csprogs.dat installed, and if so, set the csqc_progcrc accordingly, this will be sent to connecting clients to tell them to only load a matching csprogs.dat file
2583         sv.csqc_progcrc = -1;
2584         sv.csqc_progname[0] = 0;
2585         csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize);
2586         if (csprogsdata)
2587         {
2588                 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2589                 sv.csqc_progcrc = CRC_Block(csprogsdata, csprogsdatasize);
2590                 Mem_Free(csprogsdata);
2591                 Con_DPrintf("server detected csqc progs file \"%s\" with crc %i\n", sv.csqc_progname, sv.csqc_progcrc);
2592         }
2593 }
2594
2595 void SV_VM_Begin(void)
2596 {
2597         PRVM_Begin;
2598         PRVM_SetProg( PRVM_SERVERPROG );
2599
2600         *prog->time = (float) sv.time;
2601 }
2602
2603 void SV_VM_End(void)
2604 {
2605         PRVM_End;
2606 }