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