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