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