]> icculus.org git repositories - divverent/darkplaces.git/blob - sv_main.c
changed reconnect command description
[divverent/darkplaces.git] / sv_main.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // sv_main.c -- server main program
21
22 #include "quakedef.h"
23 #include "libcurl.h"
24
25 void SV_VM_Init();
26 void SV_VM_Setup();
27
28 void VM_AutoSentStats_Clear (void);
29 void EntityFrameCSQC_ClearVersions (void);
30 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
31 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
32 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
33
34
35 // select which protocol to host, this is fed to Protocol_EnumForName
36 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
37 cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
38 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
39 cvar_t sv_allowdownloads = {0, "sv_allowdownloads", "1", "whether to allow clients to download files from the server (does not affect http downloads)"};
40 cvar_t sv_allowdownloads_inarchive = {0, "sv_allowdownloads_inarchive", "0", "whether to allow downloads from archives (pak/pk3)"};
41 cvar_t sv_allowdownloads_archive = {0, "sv_allowdownloads_archive", "0", "whether to allow downloads of archives (pak/pk3)"};
42 cvar_t sv_allowdownloads_config = {0, "sv_allowdownloads_config", "0", "whether to allow downloads of config files (cfg)"};
43 cvar_t sv_allowdownloads_dlcache = {0, "sv_allowdownloads_dlcache", "0", "whether to allow downloads of dlcache files (dlcache/)"};
44
45 extern cvar_t sv_random_seed;
46
47 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
48 static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
49 static cvar_t sv_cullentities_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         trace_t trace;
814         if (sententitiesconsideration[s->number] == sententitiesmark)
815                 return;
816         sententitiesconsideration[s->number] = sententitiesmark;
817         sv_writeentitiestoclient_totalentities++;
818
819         if (s->customizeentityforclient)
820         {
821                 prog->globals.server->self = s->number;
822                 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
823                 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
824                 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
825                         return;
826         }
827
828         // never reject player
829         if (s->number != sv_writeentitiestoclient_clentnum)
830         {
831                 // check various rejection conditions
832                 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
833                         return;
834                 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
835                         return;
836                 if (s->effects & EF_NODRAW)
837                         return;
838                 // LordHavoc: only send entities with a model or important effects
839                 if (!s->modelindex && s->specialvisibilityradius == 0)
840                         return;
841
842                 isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*';
843                 // viewmodels don't have visibility checking
844                 if (s->viewmodelforclient)
845                 {
846                         if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
847                                 return;
848                 }
849                 else if (s->tagentity)
850                 {
851                         // tag attached entities simply check their parent
852                         if (!sendentitiesindex[s->tagentity])
853                                 return;
854                         SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
855                         if (sententities[s->tagentity] != sententitiesmark)
856                                 return;
857                 }
858                 // always send world submodels in newer protocols because they don't
859                 // generate much traffic (in old protocols they hog bandwidth)
860                 // but only if sv_cullentities_alwayssendbmodels is on
861                 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
862                 {
863                         // entity has survived every check so far, check if visible
864                         ed = PRVM_EDICT_NUM(s->number);
865
866                         // if not touching a visible leaf
867                         if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
868                         {
869                                 if (ed->priv.server->pvs_numclusters < 0)
870                                 {
871                                         // entity too big for clusters list
872                                         if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
873                                         {
874                                                 sv_writeentitiestoclient_culled_pvs++;
875                                                 return;
876                                         }
877                                 }
878                                 else
879                                 {
880                                         int i;
881                                         // check cached clusters list
882                                         for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
883                                                 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
884                                                         break;
885                                         if (i == ed->priv.server->pvs_numclusters)
886                                         {
887                                                 sv_writeentitiestoclient_culled_pvs++;
888                                                 return;
889                                         }
890                                 }
891                         }
892
893                         // or not seen by random tracelines
894                         if (sv_cullentities_trace.integer && !isbmodel)
895                         {
896                                 // LordHavoc: test center first
897                                 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
898                                 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
899                                 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
900                                 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
901                                 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
902                                         sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
903                                 else
904                                 {
905                                         // LordHavoc: test random offsets, to maximize chance of detection
906                                         testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
907                                         testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
908                                         testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
909                                         sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
910                                         if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
911                                                 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
912                                         else
913                                         {
914                                                 if (s->specialvisibilityradius)
915                                                 {
916                                                         // LordHavoc: test random offsets, to maximize chance of detection
917                                                         testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
918                                                         testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
919                                                         testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
920                                                         sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
921                                                         if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
922                                                                 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
923                                                 }
924                                         }
925                                 }
926                                 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
927                                 {
928                                         sv_writeentitiestoclient_culled_trace++;
929                                         return;
930                                 }
931                         }
932                 }
933         }
934
935         // this just marks it for sending
936         // FIXME: it would be more efficient to send here, but the entity
937         // compressor isn't that flexible
938         sv_writeentitiestoclient_visibleentities++;
939         sententities[s->number] = sententitiesmark;
940 }
941
942 entity_state_t sendstates[MAX_EDICTS];
943 extern int csqc_clent;
944
945 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
946 {
947         int i, numsendstates;
948         entity_state_t *s;
949
950         // if there isn't enough space to accomplish anything, skip it
951         if (msg->cursize + 25 > msg->maxsize)
952                 return;
953
954         sv_writeentitiestoclient_client = client;
955
956         sv_writeentitiestoclient_culled_pvs = 0;
957         sv_writeentitiestoclient_culled_trace = 0;
958         sv_writeentitiestoclient_visibleentities = 0;
959         sv_writeentitiestoclient_totalentities = 0;
960
961 // find the client's PVS
962         // the real place being tested from
963         VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
964         sv_writeentitiestoclient_pvsbytes = 0;
965         if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
966                 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
967
968         csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
969
970         sententitiesmark++;
971
972         for (i = 0;i < numsendentities;i++)
973                 SV_MarkWriteEntityStateToClient(sendentities + i);
974
975         numsendstates = 0;
976         for (i = 0;i < numsendentities;i++)
977         {
978                 if (sententities[sendentities[i].number] == sententitiesmark)
979                 {
980                         s = &sendstates[numsendstates++];
981                         *s = sendentities[i];
982                         if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
983                                 s->flags |= RENDER_EXTERIORMODEL;
984                 }
985         }
986
987         if (sv_cullentities_stats.integer)
988                 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);
989
990         EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
991
992         if (client->entitydatabase5)
993                 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
994         else if (client->entitydatabase4)
995                 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
996         else if (client->entitydatabase)
997                 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
998         else
999                 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
1000 }
1001
1002 /*
1003 =============
1004 SV_CleanupEnts
1005
1006 =============
1007 */
1008 void SV_CleanupEnts (void)
1009 {
1010         int             e;
1011         prvm_edict_t    *ent;
1012
1013         ent = PRVM_NEXT_EDICT(prog->edicts);
1014         for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1015                 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1016 }
1017
1018 /*
1019 ==================
1020 SV_WriteClientdataToMessage
1021
1022 ==================
1023 */
1024 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1025 {
1026         int             bits;
1027         int             i;
1028         prvm_edict_t    *other;
1029         int             items;
1030         prvm_eval_t     *val;
1031         vec3_t  punchvector;
1032         int             viewzoom;
1033         const char *s;
1034
1035 //
1036 // send a damage message
1037 //
1038         if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1039         {
1040                 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1041                 MSG_WriteByte (msg, svc_damage);
1042                 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1043                 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1044                 for (i=0 ; i<3 ; i++)
1045                         MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1046
1047                 ent->fields.server->dmg_take = 0;
1048                 ent->fields.server->dmg_save = 0;
1049         }
1050
1051 //
1052 // send the current viewpos offset from the view entity
1053 //
1054         SV_SetIdealPitch ();            // how much to look up / down ideally
1055
1056 // a fixangle might get lost in a dropped packet.  Oh well.
1057         if ( ent->fields.server->fixangle )
1058         {
1059                 MSG_WriteByte (msg, svc_setangle);
1060                 for (i=0 ; i < 3 ; i++)
1061                         MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1062                 ent->fields.server->fixangle = 0;
1063         }
1064
1065         // stuff the sigil bits into the high bits of items for sbar, or else
1066         // mix in items2
1067         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1068         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1069                 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1070         else
1071                 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1072
1073         VectorClear(punchvector);
1074         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1075                 VectorCopy(val->vector, punchvector);
1076
1077         // cache weapon model name and index in client struct to save time
1078         // (this search can be almost 1% of cpu time!)
1079         s = PRVM_GetString(ent->fields.server->weaponmodel);
1080         if (strcmp(s, client->weaponmodel))
1081         {
1082                 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1083                 client->weaponmodelindex = SV_ModelIndex(s, 1);
1084         }
1085
1086         viewzoom = 255;
1087         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1088                 viewzoom = (int)(val->_float * 255.0f);
1089         if (viewzoom == 0)
1090                 viewzoom = 255;
1091
1092         bits = 0;
1093
1094         if ((int)ent->fields.server->flags & FL_ONGROUND)
1095                 bits |= SU_ONGROUND;
1096         if (ent->fields.server->waterlevel >= 2)
1097                 bits |= SU_INWATER;
1098         if (ent->fields.server->idealpitch)
1099                 bits |= SU_IDEALPITCH;
1100
1101         for (i=0 ; i<3 ; i++)
1102         {
1103                 if (ent->fields.server->punchangle[i])
1104                         bits |= (SU_PUNCH1<<i);
1105                 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1106                         if (punchvector[i])
1107                                 bits |= (SU_PUNCHVEC1<<i);
1108                 if (ent->fields.server->velocity[i])
1109                         bits |= (SU_VELOCITY1<<i);
1110         }
1111
1112         memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1113         stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1114         stats[STAT_ITEMS] = items;
1115         stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1116         stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1117         stats[STAT_WEAPON] = client->weaponmodelindex;
1118         stats[STAT_HEALTH] = (int)ent->fields.server->health;
1119         stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1120         stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1121         stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1122         stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1123         stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1124         stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1125         stats[STAT_VIEWZOOM] = viewzoom;
1126         stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1127         stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1128         // the QC bumps these itself by sending svc_'s, so we have to keep them
1129         // zero or they'll be corrected by the engine
1130         //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1131         //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1132
1133         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)
1134         {
1135                 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1136                 bits |= SU_ITEMS;
1137                 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1138                 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1139                 bits |= SU_WEAPON;
1140                 // FIXME: which protocols support this?  does PROTOCOL_DARKPLACES3 support viewzoom?
1141                 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1142                         if (viewzoom != 255)
1143                                 bits |= SU_VIEWZOOM;
1144         }
1145
1146         if (bits >= 65536)
1147                 bits |= SU_EXTEND1;
1148         if (bits >= 16777216)
1149                 bits |= SU_EXTEND2;
1150
1151         // send the data
1152         MSG_WriteByte (msg, svc_clientdata);
1153         MSG_WriteShort (msg, bits);
1154         if (bits & SU_EXTEND1)
1155                 MSG_WriteByte(msg, bits >> 16);
1156         if (bits & SU_EXTEND2)
1157                 MSG_WriteByte(msg, bits >> 24);
1158
1159         if (bits & SU_VIEWHEIGHT)
1160                 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1161
1162         if (bits & SU_IDEALPITCH)
1163                 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1164
1165         for (i=0 ; i<3 ; i++)
1166         {
1167                 if (bits & (SU_PUNCH1<<i))
1168                 {
1169                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1170                                 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1171                         else
1172                                 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1173                 }
1174                 if (bits & (SU_PUNCHVEC1<<i))
1175                 {
1176                         if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1177                                 MSG_WriteCoord16i(msg, punchvector[i]);
1178                         else
1179                                 MSG_WriteCoord32f(msg, punchvector[i]);
1180                 }
1181                 if (bits & (SU_VELOCITY1<<i))
1182                 {
1183                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1184                                 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1185                         else
1186                                 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1187                 }
1188         }
1189
1190         if (bits & SU_ITEMS)
1191                 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1192
1193         if (sv.protocol == PROTOCOL_DARKPLACES5)
1194         {
1195                 if (bits & SU_WEAPONFRAME)
1196                         MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1197                 if (bits & SU_ARMOR)
1198                         MSG_WriteShort (msg, stats[STAT_ARMOR]);
1199                 if (bits & SU_WEAPON)
1200                         MSG_WriteShort (msg, stats[STAT_WEAPON]);
1201                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1202                 MSG_WriteShort (msg, stats[STAT_AMMO]);
1203                 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1204                 MSG_WriteShort (msg, stats[STAT_NAILS]);
1205                 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1206                 MSG_WriteShort (msg, stats[STAT_CELLS]);
1207                 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1208                 if (bits & SU_VIEWZOOM)
1209                         MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1210         }
1211         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)
1212         {
1213                 if (bits & SU_WEAPONFRAME)
1214                         MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1215                 if (bits & SU_ARMOR)
1216                         MSG_WriteByte (msg, stats[STAT_ARMOR]);
1217                 if (bits & SU_WEAPON)
1218                         MSG_WriteByte (msg, stats[STAT_WEAPON]);
1219                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1220                 MSG_WriteByte (msg, stats[STAT_AMMO]);
1221                 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1222                 MSG_WriteByte (msg, stats[STAT_NAILS]);
1223                 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1224                 MSG_WriteByte (msg, stats[STAT_CELLS]);
1225                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1226                 {
1227                         for (i = 0;i < 32;i++)
1228                                 if (stats[STAT_WEAPON] & (1<<i))
1229                                         break;
1230                         MSG_WriteByte (msg, i);
1231                 }
1232                 else
1233                         MSG_WriteByte (msg, stats[STAT_WEAPON]);
1234                 if (bits & SU_VIEWZOOM)
1235                 {
1236                         if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1237                                 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1238                         else
1239                                 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1240                 }
1241         }
1242 }
1243
1244 /*
1245 =======================
1246 SV_SendClientDatagram
1247 =======================
1248 */
1249 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1250 void SV_SendClientDatagram (client_t *client)
1251 {
1252         int rate, maxrate, maxsize, maxsize2, downloadsize;
1253         sizebuf_t msg;
1254         int stats[MAX_CL_STATS];
1255
1256         if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1257         {
1258                 // for good singleplayer, send huge packets
1259                 maxsize = sizeof(sv_sendclientdatagram_buf);
1260                 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1261         }
1262         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)
1263         {
1264                 // no rate limiting support on older protocols because dp protocols
1265                 // 1-4 kick the client off if they overflow, and quake protocol shows
1266                 // less than the full entity set if rate limited
1267                 maxsize = 1400;
1268                 maxsize2 = 1400;
1269         }
1270         else
1271         {
1272                 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1273                 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1274                 if (sv_maxrate.integer != maxrate)
1275                         Cvar_SetValueQuick(&sv_maxrate, maxrate);
1276
1277                 // this rate limiting does not understand sys_ticrate 0
1278                 // (but no one should be running that on a server!)
1279                 rate = bound(NET_MINRATE, client->rate, maxrate);
1280                 rate = (int)(rate * sys_ticrate.value);
1281                 maxsize = bound(50, rate, 1400);
1282                 maxsize2 = 1400;
1283         }
1284
1285         // while downloading, limit entity updates to half the packet
1286         // (any leftover space will be used for downloading)
1287         if (host_client->download_file)
1288                 maxsize /= 2;
1289
1290         msg.data = sv_sendclientdatagram_buf;
1291         msg.maxsize = maxsize;
1292         msg.cursize = 0;
1293
1294         if (host_client->spawned)
1295         {
1296                 MSG_WriteByte (&msg, svc_time);
1297                 MSG_WriteFloat (&msg, sv.time);
1298
1299                 // add the client specific data to the datagram
1300                 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1301                 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1302                 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1303
1304                 // expand packet size to allow effects to go over the rate limit
1305                 // (dropping them is FAR too ugly)
1306                 msg.maxsize = maxsize2;
1307
1308                 // copy the server datagram if there is space
1309                 // FIXME: put in delayed queue of effects to send
1310                 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1311                         SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1312         }
1313         else if (realtime > client->keepalivetime)
1314         {
1315                 // the player isn't totally in the game yet
1316                 // send small keepalive messages if too much time has passed
1317                 msg.maxsize = maxsize2;
1318                 client->keepalivetime = realtime + 5;
1319                 MSG_WriteChar (&msg, svc_nop);
1320         }
1321
1322         msg.maxsize = maxsize2;
1323
1324         // if a download is active, see if there is room to fit some download data
1325         // in this packet
1326         downloadsize = maxsize * 2 - msg.cursize - 7;
1327         if (host_client->download_file && host_client->download_started && downloadsize > 0)
1328         {
1329                 fs_offset_t downloadstart;
1330                 unsigned char data[1400];
1331                 downloadstart = FS_Tell(host_client->download_file);
1332                 downloadsize = min(downloadsize, (int)sizeof(data));
1333                 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1334                 // note this sends empty messages if at the end of the file, which is
1335                 // necessary to keep the packet loss logic working
1336                 // (the last blocks may be lost and need to be re-sent, and that will
1337                 //  only occur if the client acks the empty end messages, revealing
1338                 //  a gap in the download progress, causing the last blocks to be
1339                 //  sent again)
1340                 MSG_WriteChar (&msg, svc_downloaddata);
1341                 MSG_WriteLong (&msg, downloadstart);
1342                 MSG_WriteShort (&msg, downloadsize);
1343                 if (downloadsize > 0)
1344                         SZ_Write (&msg, data, downloadsize);
1345         }
1346
1347 // send the datagram
1348         NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1349 }
1350
1351 /*
1352 =======================
1353 SV_UpdateToReliableMessages
1354 =======================
1355 */
1356 void SV_UpdateToReliableMessages (void)
1357 {
1358         int i, j;
1359         client_t *client;
1360         prvm_eval_t *val;
1361         const char *name;
1362         const char *model;
1363         const char *skin;
1364
1365 // check for changes to be sent over the reliable streams
1366         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1367         {
1368                 // update the host_client fields we care about according to the entity fields
1369                 host_client->edict = PRVM_EDICT_NUM(i+1);
1370
1371                 // DP_SV_CLIENTNAME
1372                 name = PRVM_GetString(host_client->edict->fields.server->netname);
1373                 if (name == NULL)
1374                         name = "";
1375                 // always point the string back at host_client->name to keep it safe
1376                 strlcpy (host_client->name, name, sizeof (host_client->name));
1377                 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1378                 if (strcmp(host_client->old_name, host_client->name))
1379                 {
1380                         if (host_client->spawned)
1381                                 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1382                         strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1383                         // send notification to all clients
1384                         MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1385                         MSG_WriteByte (&sv.reliable_datagram, i);
1386                         MSG_WriteString (&sv.reliable_datagram, host_client->name);
1387                 }
1388
1389                 // DP_SV_CLIENTCOLORS
1390                 // this is always found (since it's added by the progs loader)
1391                 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1392                         host_client->colors = (int)val->_float;
1393                 if (host_client->old_colors != host_client->colors)
1394                 {
1395                         host_client->old_colors = host_client->colors;
1396                         // send notification to all clients
1397                         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1398                         MSG_WriteByte (&sv.reliable_datagram, i);
1399                         MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1400                 }
1401
1402                 // NEXUIZ_PLAYERMODEL
1403                 if( prog->fieldoffsets.playermodel >= 0 ) {
1404                         model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1405                         if (model == NULL)
1406                                 model = "";
1407                         // always point the string back at host_client->name to keep it safe
1408                         strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1409                         PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1410                 }
1411
1412                 // NEXUIZ_PLAYERSKIN
1413                 if( prog->fieldoffsets.playerskin >= 0 ) {
1414                         skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1415                         if (skin == NULL)
1416                                 skin = "";
1417                         // always point the string back at host_client->name to keep it safe
1418                         strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1419                         PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1420                 }
1421
1422                 // frags
1423                 host_client->frags = (int)host_client->edict->fields.server->frags;
1424                 if (host_client->old_frags != host_client->frags)
1425                 {
1426                         host_client->old_frags = host_client->frags;
1427                         // send notification to all clients
1428                         MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1429                         MSG_WriteByte (&sv.reliable_datagram, i);
1430                         MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1431                 }
1432         }
1433
1434         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1435                 if (client->netconnection)
1436                         SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1437
1438         SZ_Clear (&sv.reliable_datagram);
1439 }
1440
1441
1442 /*
1443 =======================
1444 SV_SendClientMessages
1445 =======================
1446 */
1447 void SV_SendClientMessages (void)
1448 {
1449         int i, prepared = false;
1450
1451         if (sv.protocol == PROTOCOL_QUAKEWORLD)
1452                 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1453
1454 // update frags, names, etc
1455         SV_UpdateToReliableMessages();
1456
1457 // build individual updates
1458         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1459         {
1460                 if (!host_client->active)
1461                         continue;
1462                 if (!host_client->netconnection)
1463                         continue;
1464
1465                 if (host_client->netconnection->message.overflowed)
1466                 {
1467                         SV_DropClient (true);   // if the message couldn't send, kick off
1468                         continue;
1469                 }
1470
1471                 if (!prepared)
1472                 {
1473                         prepared = true;
1474                         // only prepare entities once per frame
1475                         SV_PrepareEntitiesForSending();
1476                 }
1477                 SV_SendClientDatagram (host_client);
1478         }
1479
1480 // clear muzzle flashes
1481         SV_CleanupEnts();
1482 }
1483
1484 void SV_StartDownload_f(void)
1485 {
1486         if (host_client->download_file)
1487                 host_client->download_started = true;
1488 }
1489
1490 void SV_Download_f(void)
1491 {
1492         const char *whichpack, *whichpack2, *extension;
1493
1494         if (Cmd_Argc() != 2)
1495         {
1496                 SV_ClientPrintf("usage: download <filename>\n");
1497                 return;
1498         }
1499
1500         if (FS_CheckNastyPath(Cmd_Argv(1), false))
1501         {
1502                 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1503                 return;
1504         }
1505
1506         if (host_client->download_file)
1507         {
1508                 // at this point we'll assume the previous download should be aborted
1509                 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1510                 Host_ClientCommands("\nstopdownload\n");
1511
1512                 // close the file and reset variables
1513                 FS_Close(host_client->download_file);
1514                 host_client->download_file = NULL;
1515                 host_client->download_name[0] = 0;
1516                 host_client->download_expectedposition = 0;
1517                 host_client->download_started = false;
1518         }
1519
1520         if (!sv_allowdownloads.integer)
1521         {
1522                 SV_ClientPrintf("Downloads are disabled on this server\n");
1523                 Host_ClientCommands("\nstopdownload\n");
1524                 return;
1525         }
1526
1527         strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1528         extension = FS_FileExtension(host_client->download_name);
1529
1530         // host_client is asking to download a specified file
1531         if (developer.integer >= 100)
1532                 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1533
1534         if (!FS_FileExists(host_client->download_name))
1535         {
1536                 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);
1537                 Host_ClientCommands("\nstopdownload\n");
1538                 return;
1539         }
1540
1541         // check if the user is trying to download part of registered Quake(r)
1542         whichpack = FS_WhichPack(host_client->download_name);
1543         whichpack2 = FS_WhichPack("gfx/pop.lmp");
1544         if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1545         {
1546                 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);
1547                 Host_ClientCommands("\nstopdownload\n");
1548                 return;
1549         }
1550
1551         // check if the server has forbidden archive downloads entirely
1552         if (!sv_allowdownloads_inarchive.integer)
1553         {
1554                 whichpack = FS_WhichPack(host_client->download_name);
1555                 if (whichpack)
1556                 {
1557                         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);
1558                         Host_ClientCommands("\nstopdownload\n");
1559                         return;
1560                 }
1561         }
1562
1563         if (!sv_allowdownloads_config.integer)
1564         {
1565                 if (!strcasecmp(extension, "cfg"))
1566                 {
1567                         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);
1568                         Host_ClientCommands("\nstopdownload\n");
1569                         return;
1570                 }
1571         }
1572
1573         if (!sv_allowdownloads_dlcache.integer)
1574         {
1575                 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1576                 {
1577                         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);
1578                         Host_ClientCommands("\nstopdownload\n");
1579                         return;
1580                 }
1581         }
1582
1583         if (!sv_allowdownloads_archive.integer)
1584         {
1585                 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1586                 {
1587                         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);
1588                         Host_ClientCommands("\nstopdownload\n");
1589                         return;
1590                 }
1591         }
1592
1593         host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1594         if (!host_client->download_file)
1595         {
1596                 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1597                 Host_ClientCommands("\nstopdownload\n");
1598                 return;
1599         }
1600
1601         if (FS_FileSize(host_client->download_file) > 1<<30)
1602         {
1603                 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1604                 Host_ClientCommands("\nstopdownload\n");
1605                 FS_Close(host_client->download_file);
1606                 host_client->download_file = NULL;
1607                 return;
1608         }
1609
1610         Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1611
1612         Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1613
1614         host_client->download_expectedposition = 0;
1615         host_client->download_started = false;
1616
1617         // the rest of the download process is handled in SV_SendClientDatagram
1618         // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1619         //
1620         // no svc_downloaddata messages will be sent until sv_startdownload is
1621         // sent by the client
1622 }
1623
1624 /*
1625 ==============================================================================
1626
1627 SERVER SPAWNING
1628
1629 ==============================================================================
1630 */
1631
1632 /*
1633 ================
1634 SV_ModelIndex
1635
1636 ================
1637 */
1638 int SV_ModelIndex(const char *s, int precachemode)
1639 {
1640         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1641         char filename[MAX_QPATH];
1642         if (!s || !*s)
1643                 return 0;
1644         // testing
1645         //if (precachemode == 2)
1646         //      return 0;
1647         strlcpy(filename, s, sizeof(filename));
1648         for (i = 2;i < limit;i++)
1649         {
1650                 if (!sv.model_precache[i][0])
1651                 {
1652                         if (precachemode)
1653                         {
1654                                 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))
1655                                 {
1656                                         Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1657                                         return 0;
1658                                 }
1659                                 if (precachemode == 1)
1660                                         Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1661                                 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1662                                 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1663                                 if (sv.state != ss_loading)
1664                                 {
1665                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1666                                         MSG_WriteShort(&sv.reliable_datagram, i);
1667                                         MSG_WriteString(&sv.reliable_datagram, filename);
1668                                 }
1669                                 return i;
1670                         }
1671                         Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1672                         return 0;
1673                 }
1674                 if (!strcmp(sv.model_precache[i], filename))
1675                         return i;
1676         }
1677         Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1678         return 0;
1679 }
1680
1681 /*
1682 ================
1683 SV_SoundIndex
1684
1685 ================
1686 */
1687 int SV_SoundIndex(const char *s, int precachemode)
1688 {
1689         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1690         char filename[MAX_QPATH];
1691         if (!s || !*s)
1692                 return 0;
1693         // testing
1694         //if (precachemode == 2)
1695         //      return 0;
1696         strlcpy(filename, s, sizeof(filename));
1697         for (i = 1;i < limit;i++)
1698         {
1699                 if (!sv.sound_precache[i][0])
1700                 {
1701                         if (precachemode)
1702                         {
1703                                 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))
1704                                 {
1705                                         Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1706                                         return 0;
1707                                 }
1708                                 if (precachemode == 1)
1709                                         Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1710                                 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1711                                 if (sv.state != ss_loading)
1712                                 {
1713                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1714                                         MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1715                                         MSG_WriteString(&sv.reliable_datagram, filename);
1716                                 }
1717                                 return i;
1718                         }
1719                         Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1720                         return 0;
1721                 }
1722                 if (!strcmp(sv.sound_precache[i], filename))
1723                         return i;
1724         }
1725         Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1726         return 0;
1727 }
1728
1729 // MUST match effectnameindex_t in client.h
1730 static const char *standardeffectnames[EFFECT_TOTAL] =
1731 {
1732         "",
1733         "TE_GUNSHOT",
1734         "TE_GUNSHOTQUAD",
1735         "TE_SPIKE",
1736         "TE_SPIKEQUAD",
1737         "TE_SUPERSPIKE",
1738         "TE_SUPERSPIKEQUAD",
1739         "TE_WIZSPIKE",
1740         "TE_KNIGHTSPIKE",
1741         "TE_EXPLOSION",
1742         "TE_EXPLOSIONQUAD",
1743         "TE_TAREXPLOSION",
1744         "TE_TELEPORT",
1745         "TE_LAVASPLASH",
1746         "TE_SMALLFLASH",
1747         "TE_FLAMEJET",
1748         "EF_FLAME",
1749         "TE_BLOOD",
1750         "TE_SPARK",
1751         "TE_PLASMABURN",
1752         "TE_TEI_G3",
1753         "TE_TEI_SMOKE",
1754         "TE_TEI_BIGEXPLOSION",
1755         "TE_TEI_PLASMAHIT",
1756         "EF_STARDUST",
1757         "TR_ROCKET",
1758         "TR_GRENADE",
1759         "TR_BLOOD",
1760         "TR_WIZSPIKE",
1761         "TR_SLIGHTBLOOD",
1762         "TR_KNIGHTSPIKE",
1763         "TR_VORESPIKE",
1764         "TR_NEHAHRASMOKE",
1765         "TR_NEXUIZPLASMA",
1766         "TR_GLOWTRAIL",
1767         "SVC_PARTICLE"
1768 };
1769
1770 /*
1771 ================
1772 SV_ParticleEffectIndex
1773
1774 ================
1775 */
1776 int SV_ParticleEffectIndex(const char *name)
1777 {
1778         int i, argc, linenumber, effectnameindex;
1779         fs_offset_t filesize;
1780         unsigned char *filedata;
1781         const char *text, *textstart, *textend;
1782         char argv[16][1024];
1783         if (!sv.particleeffectnamesloaded)
1784         {
1785                 sv.particleeffectnamesloaded = true;
1786                 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
1787                 for (i = 0;i < EFFECT_TOTAL;i++)
1788                         strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
1789                 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
1790                 if (filedata)
1791                 {
1792                         textstart = (const char *)filedata;
1793                         textend = (const char *)filedata + filesize;
1794                         text = textstart;
1795                         for (linenumber = 1;;linenumber++)
1796                         {
1797                                 argc = 0;
1798                                 for (;;)
1799                                 {
1800                                         if (!COM_ParseToken(&text, true) || !strcmp(com_token, "\n"))
1801                                                 break;
1802                                         if (argc < 16)
1803                                         {
1804                                                 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
1805                                                 argc++;
1806                                         }
1807                                 }
1808                                 if (com_token[0] == 0)
1809                                         break; // if the loop exited and it's not a \n, it's EOF
1810                                 if (argc < 1)
1811                                         continue;
1812                                 if (!strcmp(argv[0], "effect"))
1813                                 {
1814                                         if (argc == 2)
1815                                         {
1816                                                 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
1817                                                 {
1818                                                         if (sv.particleeffectname[effectnameindex][0])
1819                                                         {
1820                                                                 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
1821                                                                         break;
1822                                                         }
1823                                                         else
1824                                                         {
1825                                                                 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
1826                                                                 break;
1827                                                         }
1828                                                 }
1829                                                 // if we run out of names, abort
1830                                                 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
1831                                                 {
1832                                                         Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
1833                                                         break;
1834                                                 }
1835                                         }
1836                                 }
1837                         }
1838                         Mem_Free(filedata);
1839                 }
1840         }
1841         // search for the name
1842         for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
1843                 if (!strcmp(sv.particleeffectname[effectnameindex], name))
1844                         return effectnameindex;
1845         // return 0 if we couldn't find it
1846         return 0;
1847 }
1848
1849 /*
1850 ================
1851 SV_CreateBaseline
1852
1853 ================
1854 */
1855 void SV_CreateBaseline (void)
1856 {
1857         int i, entnum, large;
1858         prvm_edict_t *svent;
1859
1860         // LordHavoc: clear *all* states (note just active ones)
1861         for (entnum = 0;entnum < prog->max_edicts;entnum++)
1862         {
1863                 // get the current server version
1864                 svent = PRVM_EDICT_NUM(entnum);
1865
1866                 // LordHavoc: always clear state values, whether the entity is in use or not
1867                 svent->priv.server->baseline = defaultstate;
1868
1869                 if (svent->priv.server->free)
1870                         continue;
1871                 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1872                         continue;
1873
1874                 // create entity baseline
1875                 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1876                 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1877                 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1878                 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1879                 if (entnum > 0 && entnum <= svs.maxclients)
1880                 {
1881                         svent->priv.server->baseline.colormap = entnum;
1882                         svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1883                 }
1884                 else
1885                 {
1886                         svent->priv.server->baseline.colormap = 0;
1887                         svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1888                 }
1889
1890                 large = false;
1891                 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1892                         large = true;
1893
1894                 // add to the message
1895                 if (large)
1896                         MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1897                 else
1898                         MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1899                 MSG_WriteShort (&sv.signon, entnum);
1900
1901                 if (large)
1902                 {
1903                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1904                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1905                 }
1906                 else
1907                 {
1908                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1909                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1910                 }
1911                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1912                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1913                 for (i=0 ; i<3 ; i++)
1914                 {
1915                         MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1916                         MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1917                 }
1918         }
1919 }
1920
1921
1922 /*
1923 ================
1924 SV_SaveSpawnparms
1925
1926 Grabs the current state of each client for saving across the
1927 transition to another level
1928 ================
1929 */
1930 void SV_SaveSpawnparms (void)
1931 {
1932         int             i, j;
1933
1934         svs.serverflags = (int)prog->globals.server->serverflags;
1935
1936         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1937         {
1938                 if (!host_client->active)
1939                         continue;
1940
1941         // call the progs to get default spawn parms for the new client
1942                 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1943                 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1944                 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1945                         host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1946         }
1947 }
1948 /*
1949 void SV_IncreaseEdicts(void)
1950 {
1951         int i;
1952         prvm_edict_t *ent;
1953         int oldmax_edicts = prog->max_edicts;
1954         void *oldedictsengineprivate = prog->edictprivate;
1955         void *oldedictsfields = prog->edictsfields;
1956         void *oldmoved_edicts = sv.moved_edicts;
1957
1958         if (prog->max_edicts >= MAX_EDICTS)
1959                 return;
1960
1961         // links don't survive the transition, so unlink everything
1962         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1963         {
1964                 if (!ent->priv.server->free)
1965                         SV_UnlinkEdict(prog->edicts + i);
1966                 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1967         }
1968         World_Clear(&sv.world);
1969
1970         prog->max_edicts   = min(prog->max_edicts + 256, MAX_EDICTS);
1971         prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1972         prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1973         sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1974
1975         memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1976         memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1977
1978         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1979         {
1980                 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1981                 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1982                 // link every entity except world
1983                 if (!ent->priv.server->free)
1984                         SV_LinkEdict(ent, false);
1985         }
1986
1987         PR_Free(oldedictsengineprivate);
1988         PR_Free(oldedictsfields);
1989         PR_Free(oldmoved_edicts);
1990 }*/
1991
1992 /*
1993 ================
1994 SV_SpawnServer
1995
1996 This is called at the start of each level
1997 ================
1998 */
1999 extern float            scr_centertime_off;
2000
2001 void SV_SpawnServer (const char *server)
2002 {
2003         prvm_edict_t *ent;
2004         int i;
2005         char *entities;
2006         model_t *worldmodel;
2007         char modelname[sizeof(sv.modelname)];
2008
2009         Con_DPrintf("SpawnServer: %s\n", server);
2010
2011         if (cls.state != ca_dedicated)
2012                 SCR_BeginLoadingPlaque();
2013
2014         dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2015         worldmodel = Mod_ForName(modelname, false, true, true);
2016         if (!worldmodel || !worldmodel->TraceBox)
2017         {
2018                 Con_Printf("Couldn't load map %s\n", modelname);
2019                 return;
2020         }
2021
2022         // let's not have any servers with no name
2023         if (hostname.string[0] == 0)
2024                 Cvar_Set ("hostname", "UNNAMED");
2025         scr_centertime_off = 0;
2026
2027         svs.changelevel_issued = false;         // now safe to issue another
2028
2029         // make the map a required file for clients
2030         Curl_ClearRequirements();
2031         Curl_RequireFile(modelname);
2032
2033 //
2034 // tell all connected clients that we are going to a new level
2035 //
2036         if (sv.active)
2037         {
2038                 client_t *client;
2039                 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2040                 {
2041                         if (client->netconnection)
2042                         {
2043                                 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2044                                 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2045                         }
2046                 }
2047         }
2048         else
2049         {
2050                 // open server port
2051                 NetConn_OpenServerPorts(true);
2052         }
2053
2054 //
2055 // make cvars consistant
2056 //
2057         if (coop.integer)
2058                 Cvar_SetValue ("deathmatch", 0);
2059         // LordHavoc: it can be useful to have skills outside the range 0-3...
2060         //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2061         //Cvar_SetValue ("skill", (float)current_skill);
2062         current_skill = (int)(skill.value + 0.5);
2063
2064 //
2065 // set up the new server
2066 //
2067         memset (&sv, 0, sizeof(sv));
2068         // if running a local client, make sure it doesn't try to access the last
2069         // level's data which is no longer valiud
2070         cls.signon = 0;
2071
2072         if(*sv_random_seed.string)
2073         {
2074                 srand(sv_random_seed.integer);
2075                 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);
2076         }
2077
2078         SV_VM_Setup();
2079
2080         sv.active = true;
2081
2082         strlcpy (sv.name, server, sizeof (sv.name));
2083
2084         sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2085         if (sv.protocol == PROTOCOL_UNKNOWN)
2086         {
2087                 char buffer[1024];
2088                 Protocol_Names(buffer, sizeof(buffer));
2089                 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2090                 sv.protocol = PROTOCOL_QUAKE;
2091         }
2092
2093         SV_VM_Begin();
2094
2095 // load progs to get entity field count
2096         //PR_LoadProgs ( sv_progs.string );
2097
2098         // allocate server memory
2099         /*// start out with just enough room for clients and a reasonable estimate of entities
2100         prog->max_edicts = max(svs.maxclients + 1, 512);
2101         prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
2102
2103         // prvm_edict_t structures (hidden from progs)
2104         prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
2105         // engine private structures (hidden from progs)
2106         prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2107         // progs fields, often accessed by server
2108         prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
2109         // used by PushMove to move back pushed entities
2110         sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2111         /*for (i = 0;i < prog->max_edicts;i++)
2112         {
2113                 ent = prog->edicts + i;
2114                 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2115                 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2116         }*/
2117
2118         // reset client csqc entity versions right away.
2119         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2120                 EntityFrameCSQC_InitClientVersions(i, true);
2121
2122         sv.datagram.maxsize = sizeof(sv.datagram_buf);
2123         sv.datagram.cursize = 0;
2124         sv.datagram.data = sv.datagram_buf;
2125
2126         sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2127         sv.reliable_datagram.cursize = 0;
2128         sv.reliable_datagram.data = sv.reliable_datagram_buf;
2129
2130         sv.signon.maxsize = sizeof(sv.signon_buf);
2131         sv.signon.cursize = 0;
2132         sv.signon.data = sv.signon_buf;
2133
2134 // leave slots at start for clients only
2135         //prog->num_edicts = svs.maxclients+1;
2136
2137         sv.state = ss_loading;
2138         prog->allowworldwrites = true;
2139         sv.paused = false;
2140
2141         prog->globals.server->time = sv.time = 1.0;
2142
2143         Mod_ClearUsed();
2144         worldmodel->used = true;
2145
2146         strlcpy (sv.name, server, sizeof (sv.name));
2147         strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2148         sv.worldmodel = worldmodel;
2149         sv.models[1] = sv.worldmodel;
2150
2151 //
2152 // clear world interaction links
2153 //
2154         VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2155         VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2156         World_Clear(&sv.world);
2157
2158         strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2159
2160         strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2161         strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2162         for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2163         {
2164                 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2165                 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2166         }
2167
2168 //
2169 // load the rest of the entities
2170 //
2171         // AK possible hack since num_edicts is still 0
2172         ent = PRVM_EDICT_NUM(0);
2173         memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2174         ent->priv.server->free = false;
2175         ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2176         ent->fields.server->modelindex = 1;             // world model
2177         ent->fields.server->solid = SOLID_BSP;
2178         ent->fields.server->movetype = MOVETYPE_PUSH;
2179         VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2180         VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2181         VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2182         VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2183
2184         if (coop.value)
2185                 prog->globals.server->coop = coop.integer;
2186         else
2187                 prog->globals.server->deathmatch = deathmatch.integer;
2188
2189         prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2190
2191 // serverflags are for cross level information (sigils)
2192         prog->globals.server->serverflags = svs.serverflags;
2193
2194         // we need to reset the spawned flag on all connected clients here so that
2195         // their thinks don't run during startup (before PutClientInServer)
2196         // we also need to set up the client entities now
2197         // and we need to set the ->edict pointers to point into the progs edicts
2198         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2199         {
2200                 host_client->spawned = false;
2201                 host_client->edict = PRVM_EDICT_NUM(i + 1);
2202                 PRVM_ED_ClearEdict(host_client->edict);
2203         }
2204
2205         // load replacement entity file if found
2206         if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2207         {
2208                 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2209                 PRVM_ED_LoadFromFile (entities);
2210                 Mem_Free(entities);
2211         }
2212         else
2213                 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2214
2215
2216         // LordHavoc: clear world angles (to fix e3m3.bsp)
2217         VectorClear(prog->edicts->fields.server->angles);
2218
2219 // all setup is completed, any further precache statements are errors
2220         sv.state = ss_active;
2221         prog->allowworldwrites = false;
2222
2223 // run two frames to allow everything to settle
2224         for (i = 0;i < 2;i++)
2225         {
2226                 sv.frametime = 0.1;
2227                 SV_Physics ();
2228         }
2229
2230         Mod_PurgeUnused();
2231
2232 // create a baseline for more efficient communications
2233         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2234                 SV_CreateBaseline ();
2235
2236 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2237         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2238         {
2239                 if (!host_client->active)
2240                         continue;
2241                 if (host_client->netconnection)
2242                         SV_SendServerinfo(host_client);
2243                 else
2244                 {
2245                         int j;
2246                         // if client is a botclient coming from a level change, we need to
2247                         // set up client info that normally requires networking
2248
2249                         // copy spawn parms out of the client_t
2250                         for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2251                                 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2252
2253                         // call the spawn function
2254                         host_client->clientconnectcalled = true;
2255                         prog->globals.server->time = sv.time;
2256                         prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2257                         PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2258                         PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2259                         host_client->spawned = true;
2260                 }
2261         }
2262
2263         Con_DPrint("Server spawned.\n");
2264         NetConn_Heartbeat (2);
2265
2266         SV_VM_End();
2267 }
2268
2269 /////////////////////////////////////////////////////
2270 // SV VM stuff
2271
2272 void SV_VM_CB_BeginIncreaseEdicts(void)
2273 {
2274         int i;
2275         prvm_edict_t *ent;
2276
2277         PRVM_Free( sv.moved_edicts );
2278         sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2279
2280         // links don't survive the transition, so unlink everything
2281         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2282         {
2283                 if (!ent->priv.server->free)
2284                         World_UnlinkEdict(prog->edicts + i);
2285                 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2286         }
2287         World_Clear(&sv.world);
2288 }
2289
2290 void SV_VM_CB_EndIncreaseEdicts(void)
2291 {
2292         int i;
2293         prvm_edict_t *ent;
2294
2295         // link every entity except world
2296         for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2297                 if (!ent->priv.server->free)
2298                         SV_LinkEdict(ent, false);
2299 }
2300
2301 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2302 {
2303         // LordHavoc: for consistency set these here
2304         int num = PRVM_NUM_FOR_EDICT(e) - 1;
2305
2306         e->priv.server->move = false; // don't move on first frame
2307
2308         if (num >= 0 && num < svs.maxclients)
2309         {
2310                 prvm_eval_t *val;
2311                 // set colormap and team on newly created player entity
2312                 e->fields.server->colormap = num + 1;
2313                 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2314                 // set netname/clientcolors back to client values so that
2315                 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2316                 // reset them
2317                 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2318                 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2319                         val->_float = svs.clients[num].colors;
2320                 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2321                 if( prog->fieldoffsets.playermodel >= 0 )
2322                         PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2323                 if( prog->fieldoffsets.playerskin >= 0 )
2324                         PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2325         }
2326 }
2327
2328 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2329 {
2330         World_UnlinkEdict(ed);          // unlink from world bsp
2331
2332         ed->fields.server->model = 0;
2333         ed->fields.server->takedamage = 0;
2334         ed->fields.server->modelindex = 0;
2335         ed->fields.server->colormap = 0;
2336         ed->fields.server->skin = 0;
2337         ed->fields.server->frame = 0;
2338         VectorClear(ed->fields.server->origin);
2339         VectorClear(ed->fields.server->angles);
2340         ed->fields.server->nextthink = -1;
2341         ed->fields.server->solid = 0;
2342 }
2343
2344 void SV_VM_CB_CountEdicts(void)
2345 {
2346         int             i;
2347         prvm_edict_t    *ent;
2348         int             active, models, solid, step;
2349
2350         active = models = solid = step = 0;
2351         for (i=0 ; i<prog->num_edicts ; i++)
2352         {
2353                 ent = PRVM_EDICT_NUM(i);
2354                 if (ent->priv.server->free)
2355                         continue;
2356                 active++;
2357                 if (ent->fields.server->solid)
2358                         solid++;
2359                 if (ent->fields.server->model)
2360                         models++;
2361                 if (ent->fields.server->movetype == MOVETYPE_STEP)
2362                         step++;
2363         }
2364
2365         Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2366         Con_Printf("active    :%3i\n", active);
2367         Con_Printf("view      :%3i\n", models);
2368         Con_Printf("touch     :%3i\n", solid);
2369         Con_Printf("step      :%3i\n", step);
2370 }
2371
2372 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2373 {
2374         // remove things from different skill levels or deathmatch
2375         if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2376         {
2377                 if (deathmatch.integer)
2378                 {
2379                         if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2380                         {
2381                                 return false;
2382                         }
2383                 }
2384                 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY  ))
2385                         || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2386                         || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD  )))
2387                 {
2388                         return false;
2389                 }
2390         }
2391         return true;
2392 }
2393
2394 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)"};
2395 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2396 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2397 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2398 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2399 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2400 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2401 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2402 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2403 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2404 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2405 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2406 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2407 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2408 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2409 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2410 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2411 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2412 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2413 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2414 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2415 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2416 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2417 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2418 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2419 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2420 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2421 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2422 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2423 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2424 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2425 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2426 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2427
2428 void SV_VM_Init(void)
2429 {
2430         Cvar_RegisterVariable (&pr_checkextension);
2431         Cvar_RegisterVariable (&nomonsters);
2432         Cvar_RegisterVariable (&gamecfg);
2433         Cvar_RegisterVariable (&scratch1);
2434         Cvar_RegisterVariable (&scratch2);
2435         Cvar_RegisterVariable (&scratch3);
2436         Cvar_RegisterVariable (&scratch4);
2437         Cvar_RegisterVariable (&savedgamecfg);
2438         Cvar_RegisterVariable (&saved1);
2439         Cvar_RegisterVariable (&saved2);
2440         Cvar_RegisterVariable (&saved3);
2441         Cvar_RegisterVariable (&saved4);
2442         // LordHavoc: Nehahra uses these to pass data around cutscene demos
2443         if (gamemode == GAME_NEHAHRA)
2444         {
2445                 Cvar_RegisterVariable (&nehx00);
2446                 Cvar_RegisterVariable (&nehx01);
2447                 Cvar_RegisterVariable (&nehx02);
2448                 Cvar_RegisterVariable (&nehx03);
2449                 Cvar_RegisterVariable (&nehx04);
2450                 Cvar_RegisterVariable (&nehx05);
2451                 Cvar_RegisterVariable (&nehx06);
2452                 Cvar_RegisterVariable (&nehx07);
2453                 Cvar_RegisterVariable (&nehx08);
2454                 Cvar_RegisterVariable (&nehx09);
2455                 Cvar_RegisterVariable (&nehx10);
2456                 Cvar_RegisterVariable (&nehx11);
2457                 Cvar_RegisterVariable (&nehx12);
2458                 Cvar_RegisterVariable (&nehx13);
2459                 Cvar_RegisterVariable (&nehx14);
2460                 Cvar_RegisterVariable (&nehx15);
2461                 Cvar_RegisterVariable (&nehx16);
2462                 Cvar_RegisterVariable (&nehx17);
2463                 Cvar_RegisterVariable (&nehx18);
2464                 Cvar_RegisterVariable (&nehx19);
2465         }
2466         Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2467 }
2468
2469 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2470
2471 prvm_required_field_t reqfields[] =
2472 {
2473         {ev_entity, "cursor_trace_ent"},
2474         {ev_entity, "drawonlytoclient"},
2475         {ev_entity, "exteriormodeltoclient"},
2476         {ev_entity, "nodrawtoclient"},
2477         {ev_entity, "tag_entity"},
2478         {ev_entity, "viewmodelforclient"},
2479         {ev_float, "alpha"},
2480         {ev_float, "ammo_cells1"},
2481         {ev_float, "ammo_lava_nails"},
2482         {ev_float, "ammo_multi_rockets"},
2483         {ev_float, "ammo_nails1"},
2484         {ev_float, "ammo_plasma"},
2485         {ev_float, "ammo_rockets1"},
2486         {ev_float, "ammo_shells1"},
2487         {ev_float, "button3"},
2488         {ev_float, "button4"},
2489         {ev_float, "button5"},
2490         {ev_float, "button6"},
2491         {ev_float, "button7"},
2492         {ev_float, "button8"},
2493         {ev_float, "button9"},
2494         {ev_float, "button10"},
2495         {ev_float, "button11"},
2496         {ev_float, "button12"},
2497         {ev_float, "button13"},
2498         {ev_float, "button14"},
2499         {ev_float, "button15"},
2500         {ev_float, "button16"},
2501         {ev_float, "buttonchat"},
2502         {ev_float, "buttonuse"},
2503         {ev_float, "clientcolors"},
2504         {ev_float, "cursor_active"},
2505         {ev_float, "fullbright"},
2506         {ev_float, "glow_color"},
2507         {ev_float, "glow_size"},
2508         {ev_float, "glow_trail"},
2509         {ev_float, "gravity"},
2510         {ev_float, "idealpitch"},
2511         {ev_float, "items2"},
2512         {ev_float, "light_lev"},
2513         {ev_float, "pflags"},
2514         {ev_float, "ping"},
2515         {ev_float, "pitch_speed"},
2516         {ev_float, "pmodel"},
2517         {ev_float, "renderamt"}, // HalfLife support
2518         {ev_float, "rendermode"}, // HalfLife support
2519         {ev_float, "scale"},
2520         {ev_float, "style"},
2521         {ev_float, "tag_index"},
2522         {ev_float, "Version"},
2523         {ev_float, "viewzoom"},
2524         {ev_vector, "color"},
2525         {ev_vector, "colormod"},
2526         {ev_vector, "cursor_screen"},
2527         {ev_vector, "cursor_trace_endpos"},
2528         {ev_vector, "cursor_trace_start"},
2529         {ev_vector, "movement"},
2530         {ev_vector, "punchvector"},
2531         {ev_string, "playermodel"},
2532         {ev_string, "playerskin"},
2533         {ev_function, "SendEntity"},
2534         {ev_function, "customizeentityforclient"},
2535         // DRESK - Support for Entity Contents Transition Event
2536         {ev_function, "contentstransition"},
2537 };
2538
2539 void SV_VM_Setup(void)
2540 {
2541         extern cvar_t csqc_progname;    //[515]: csqc crc check and right csprogs name according to progs.dat
2542         extern cvar_t csqc_progcrc;
2543         extern cvar_t csqc_progsize;
2544         size_t csprogsdatasize;
2545         PRVM_Begin;
2546         PRVM_InitProg( PRVM_SERVERPROG );
2547
2548         // allocate the mempools
2549         // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2550         prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2551         prog->builtins = vm_sv_builtins;
2552         prog->numbuiltins = vm_sv_numbuiltins;
2553         prog->headercrc = PROGHEADER_CRC;
2554         prog->max_edicts = 512;
2555         prog->limit_edicts = MAX_EDICTS;
2556         prog->reserved_edicts = svs.maxclients;
2557         prog->edictprivate_size = sizeof(edict_engineprivate_t);
2558         prog->name = "server";
2559         prog->extensionstring = vm_sv_extensions;
2560         prog->loadintoworld = true;
2561
2562         prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2563         prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2564         prog->init_edict = SV_VM_CB_InitEdict;
2565         prog->free_edict = SV_VM_CB_FreeEdict;
2566         prog->count_edicts = SV_VM_CB_CountEdicts;
2567         prog->load_edict = SV_VM_CB_LoadEdict;
2568         prog->init_cmd = VM_SV_Cmd_Init;
2569         prog->reset_cmd = VM_SV_Cmd_Reset;
2570         prog->error_cmd = Host_Error;
2571
2572         // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2573         PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2574
2575         // some mods compiled with scrambling compilers lack certain critical
2576         // global names and field names such as "self" and "time" and "nextthink"
2577         // so we have to set these offsets manually, matching the entvars_t
2578         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2579         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2580         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2581         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2582         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2583         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2584         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2585         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2586         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2587         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2588         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2589         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2590         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2591         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2592         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2593         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2594         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2595         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2596         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2597         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2598         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2599         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2600         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2601         // OP_STATE is always supported on server (due to entvars_t)
2602         prog->flag |= PRVM_OP_STATE;
2603
2604         VM_AutoSentStats_Clear();//[515]: csqc
2605         EntityFrameCSQC_ClearVersions();//[515]: csqc
2606
2607         PRVM_End;
2608
2609         // 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
2610         sv.csqc_progname[0] = 0;
2611         sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2612         sv.csqc_progsize = csprogsdatasize;
2613         if (sv.csqc_progsize > 0)
2614         {
2615                 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2616                 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2617         }
2618 }
2619
2620 void SV_VM_Begin(void)
2621 {
2622         PRVM_Begin;
2623         PRVM_SetProg( PRVM_SERVERPROG );
2624
2625         prog->globals.server->time = (float) sv.time;
2626 }
2627
2628 void SV_VM_End(void)
2629 {
2630         PRVM_End;
2631 }