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