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