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