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