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