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