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