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