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