2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // sv_main.c -- server main program
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();
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);
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/)"};
46 extern cvar_t sv_random_seed;
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)"};
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)"};
71 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
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"};
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;
116 mempool_t *sv_mempool = NULL;
118 extern cvar_t slowmo;
119 extern float scr_centertime_off;
121 // MUST match effectnameindex_t in client.h
122 static const char *standardeffectnames[EFFECT_TOTAL] =
146 "TE_TEI_BIGEXPLOSION",
162 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
164 prvm_required_field_t reqfields[] =
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"},
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"},
211 {ev_float, "pitch_speed"},
212 {ev_float, "pmodel"},
213 {ev_float, "renderamt"}, // HalfLife support
214 {ev_float, "rendermode"}, // HalfLife support
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"},
236 //============================================================================
238 void SV_AreaStats_f(void)
240 World_PrintAreaStats(&sv.world, "server");
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);
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);
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)
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);
351 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
355 sv_mempool = Mem_AllocPool("server", 0, NULL);
358 static void SV_SaveEntFile_f(void)
360 char basename[MAX_QPATH];
361 if (!sv.active || !sv.worldmodel)
363 Con_Print("Not running a server\n");
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));
372 =============================================================================
376 =============================================================================
383 Make sure the event gets sent to all clients
386 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
390 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
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();
407 Make sure the event gets sent to all clients
410 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
412 if (modelindex >= 256 || startframe >= 256)
414 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
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);
427 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
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);
438 SV_FlushBroadcastMessages();
445 Each entity can have eight independant sound sources, like voice,
448 Channel 0 is an auto-allocate channel, the others override anything
449 already running on that entity/channel pair.
451 An attenuation of 0 will play full volume everywhere in the level.
452 Larger attenuations will drop off. (max 4 attenuation)
456 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
458 int sound_num, field_mask, i, ent;
460 if (volume < 0 || volume > 255)
462 Con_Printf ("SV_StartSound: volume = %i\n", volume);
466 if (attenuation < 0 || attenuation > 4)
468 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
472 if (channel < 0 || channel > 7)
474 Con_Printf ("SV_StartSound: channel = %i\n", channel);
478 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
481 // find precache number for sound
482 sound_num = SV_SoundIndex(sample, 1);
486 ent = PRVM_NUM_FOR_EDICT(entity);
489 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
490 field_mask |= SND_VOLUME;
491 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
492 field_mask |= SND_ATTENUATION;
494 field_mask |= SND_LARGEENTITY;
495 if (sound_num >= 256 || channel >= 8)
496 field_mask |= SND_LARGESOUND;
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)
507 MSG_WriteShort (&sv.datagram, ent);
508 MSG_WriteByte (&sv.datagram, channel);
511 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
512 if (field_mask & SND_LARGESOUND)
513 MSG_WriteShort (&sv.datagram, sound_num);
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();
522 ==============================================================================
526 ==============================================================================
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.
537 void SV_SendServerinfo (client_t *client)
542 // we know that this client has a netconnection and thus is not a bot
544 // edicts get reallocated on level changes, so we need to update it here
545 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
547 // clear cached stuff that depends on the level
548 client->weaponmodel[0] = 0;
549 client->weaponmodelindex = 0;
551 // LordHavoc: clear entityframe tracking
552 client->latestframenum = 0;
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);
561 memset(client->stats, 0, sizeof(client->stats));
562 memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits));
564 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
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);
571 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
574 // reset csqc entity versions
575 memset(client->csqcentityversion, 0, sizeof(client->csqcentityversion));
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);
582 //[515]: init csprogs according to version of svprogs, check the crc, etc.
583 if (sv.csqc_progname[0])
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);
597 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
598 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
602 if (sv_allowdownloads.integer)
604 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
605 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
608 // send at this time so it's guaranteed to get executed at the right time
612 host_client = client;
613 Curl_SendRequirements();
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);
621 if (!coop.integer && deathmatch.integer)
622 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
624 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
626 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
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);
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);
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);
642 MSG_WriteByte (&client->netconnection->message, svc_setview);
643 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
645 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
646 MSG_WriteByte (&client->netconnection->message, 1);
648 client->spawned = false; // need prespawn, spawn, etc
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;
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.
669 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
673 float spawn_parms[NUM_SPAWN_PARMS];
675 client = svs.clients + clientnum;
677 // set up the client_t
679 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
680 memset (client, 0, sizeof(*client));
681 client->active = true;
682 client->netconnection = netconnection;
684 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
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;
703 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
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];
713 // set up the entity for this client (including .colormap, .team, etc)
714 PRVM_ED_ClearEdict(client->edict);
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);
722 client->spawned = true;
727 ===============================================================================
731 ===============================================================================
735 =============================================================================
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
742 =============================================================================
745 static qboolean SV_BuildEntityState (entity_state_t *cs, prvm_edict_t *ent, int enumber)
748 unsigned int tagentity;
749 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
750 unsigned int customizeentityforclient;
752 vec3_t cullmins, cullmaxs, netcenter;
756 // see if the customizeentityforclient extension is used by this entity
757 customizeentityforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function;
758 if (customizeentityforclient)
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))
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))
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;
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;
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;
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;
802 if (gamemode == GAME_TENEBRAE)
804 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
808 lightpflags |= PFLAGS_FULLDYNAMIC;
810 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
814 light[0] = (int)(0.2*256);
815 light[1] = (int)(1.0*256);
816 light[2] = (int)(0.2*256);
818 lightpflags |= PFLAGS_FULLDYNAMIC;
822 specialvisibilityradius = 0;
823 if (lightpflags & PFLAGS_FULLDYNAMIC)
824 specialvisibilityradius = max(specialvisibilityradius, light[3]);
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))
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);
849 // don't send uninteresting entities
850 if (enumber != sv.writeentitiestoclient_cliententitynumber)
852 if (!modelindex && !specialvisibilityradius)
854 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict == sv.writeentitiestoclient_cliententitynumber)
856 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict && PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict != sv.writeentitiestoclient_cliententitynumber)
858 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict && PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict != sv.writeentitiestoclient_cliententitynumber)
860 if (flags & RENDER_VIEWMODEL && PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict != sv.writeentitiestoclient_cliententitynumber)
862 if (effects & EF_NODRAW)
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))
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]))
877 float scale = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float;
879 scale *= (1.0f / 16.0f);
882 if (ent->fields.server->angles[0] || ent->fields.server->angles[2]) // pitch and roll
884 VectorMA(ent->fields.server->origin, scale, model->rotatedmins, cullmins);
885 VectorMA(ent->fields.server->origin, scale, model->rotatedmaxs, cullmaxs);
887 else if (ent->fields.server->angles[1])
889 VectorMA(ent->fields.server->origin, scale, model->yawmins, cullmins);
890 VectorMA(ent->fields.server->origin, scale, model->yawmaxs, cullmaxs);
894 VectorMA(ent->fields.server->origin, scale, model->normalmins, cullmins);
895 VectorMA(ent->fields.server->origin, scale, model->normalmaxs, cullmaxs);
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);
904 if (specialvisibilityradius)
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);
914 // calculate center of bbox for network prioritization purposes
915 VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, netcenter);
917 // if culling box has moved, update pvs cluster links
918 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
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)
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;
935 if (enumber != sv.writeentitiestoclient_cliententitynumber && !(effects & EF_NODEPTHTEST) && !(flags & RENDER_VIEWMODEL) && !tagentity)
937 qboolean isbmodel = (model = sv.models[modelindex]) != NULL && model->name[0] == '*';
938 if (!isbmodel || !sv_cullentities_nevercullbmodels.integer)
940 // cull based on visibility
942 // if not touching a visible leaf
943 if (sv_cullentities_pvs.integer && sv.writeentitiestoclient_pvsbytes)
945 if (ent->priv.server->pvs_numclusters < 0)
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))
950 sv.writeentitiestoclient_stats_culled_pvs++;
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]))
961 if (i == ent->priv.server->pvs_numclusters)
963 sv.writeentitiestoclient_stats_culled_pvs++;
969 // or not seen by random tracelines
970 if (sv_cullentities_trace.integer && !isbmodel)
972 int samples = specialvisibilityradius ? sv_cullentities_trace_samples_extra.integer : sv_cullentities_trace_samples.integer;
973 float enlarge = sv_cullentities_trace_enlarge.value;
975 qboolean visible = true;
979 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv.writeentitiestoclient_testeye, cullmins, cullmaxs))
980 break; // directly visible from the server's view
982 if(sv_cullentities_trace_prediction.integer)
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...
994 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, cullmins, cullmaxs))
995 break; // directly visible from the predicted view
999 //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
1003 // when we get here, we can't see the entity
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])
1012 sv.writeentitiestoclient_stats_culled_trace++;
1019 // if the caller was just checking... return 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);
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;
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])
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);
1049 cs->modelindex = modelindex;
1052 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f);
1056 cs->alpha = (unsigned char)bound(0, i, 255);
1059 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
1063 cs->alpha = (unsigned char)bound(0, i, 255);
1067 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f);
1071 cs->scale = (unsigned char)bound(0, i, 255);
1074 cs->glowcolor = 254;
1075 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
1077 cs->glowcolor = (int)f;
1079 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
1080 cs->effects |= EF_FULLBRIGHT;
1082 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.modelflags);
1083 if (val && val->_float)
1084 cs->effects |= ((unsigned int)val->_float & 0xff) << 24;
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;
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;
1105 static void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg)
1111 // if there isn't enough space to accomplish anything, skip it
1112 if (msg->cursize + 25 > msg->maxsize)
1115 sv.writeentitiestoclient_msg = msg;
1116 sv.writeentitiestoclient_clientnumber = client - svs.clients;
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;
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));
1130 sv.writeentitiestoclient_cliententitynumber = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
1132 // send all entities that touch the pvs
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))
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);
1141 EntityFrameCSQC_WriteFrame(msg, numsendstates, sv.writeentitiestoclient_sendstates);
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)
1147 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates);
1148 Protocol_WriteStatsReliable();
1150 else if (client->entitydatabase)
1152 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1);
1153 Protocol_WriteStatsReliable();
1157 EntityFrameQuake_WriteFrame(msg, numsendstates, sv.writeentitiestoclient_sendstates);
1158 Protocol_WriteStatsReliable();
1168 static void SV_CleanupEnts (void)
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;
1180 SV_WriteClientdataToMessage
1184 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1188 prvm_edict_t *other;
1194 float *statsf = (float *)stats;
1197 // send a damage message
1199 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
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);
1208 ent->fields.server->dmg_take = 0;
1209 ent->fields.server->dmg_save = 0;
1213 // send the current viewpos offset from the view entity
1215 SV_SetIdealPitch (); // how much to look up / down ideally
1217 // a fixangle might get lost in a dropped packet. Oh well.
1218 if(ent->fields.server->fixangle)
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;
1225 // and clear fixangle for the next frame
1226 ent->fields.server->fixangle = 0;
1229 if (host_client->fixangle_angles_set)
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;
1237 // stuff the sigil bits into the high bits of items for sbar, or else
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);
1243 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1245 VectorClear(punchvector);
1246 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1247 VectorCopy(val->vector, punchvector);
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))
1254 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1255 client->weaponmodelindex = SV_ModelIndex(s, 1);
1259 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1260 viewzoom = (int)(val->_float * 255.0f);
1266 if ((int)ent->fields.server->flags & FL_ONGROUND)
1267 bits |= SU_ONGROUND;
1268 if (ent->fields.server->waterlevel >= 2)
1270 if (ent->fields.server->idealpitch)
1271 bits |= SU_IDEALPITCH;
1273 for (i=0 ; i<3 ; i++)
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)
1279 bits |= (SU_PUNCHVEC1<<i);
1280 if (ent->fields.server->velocity[i])
1281 bits |= (SU_VELOCITY1<<i);
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;
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;
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)
1326 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1328 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1329 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
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;
1339 if (bits >= 16777216)
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);
1350 if (bits & SU_VIEWHEIGHT)
1351 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1353 if (bits & SU_IDEALPITCH)
1354 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1356 for (i=0 ; i<3 ; i++)
1358 if (bits & (SU_PUNCH1<<i))
1360 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1361 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1363 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1365 if (bits & (SU_PUNCHVEC1<<i))
1367 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1368 MSG_WriteCoord16i(msg, punchvector[i]);
1370 MSG_WriteCoord32f(msg, punchvector[i]);
1372 if (bits & (SU_VELOCITY1<<i))
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)));
1377 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1381 if (bits & SU_ITEMS)
1382 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1384 if (sv.protocol == PROTOCOL_DARKPLACES5)
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));
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)
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)
1418 for (i = 0;i < 32;i++)
1419 if (stats[STAT_WEAPON] & (1<<i))
1421 MSG_WriteByte (msg, i);
1424 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1425 if (bits & SU_VIEWZOOM)
1427 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1428 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1430 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1435 void SV_FlushBroadcastMessages(void)
1439 if (sv.datagram.cursize <= 0)
1441 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
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])))
1445 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
1446 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
1448 SZ_Clear(&sv.datagram);
1451 static void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg)
1453 // scan the splitpoints to find out how many we can fit in
1454 int numsegments, j, split;
1455 if (!client->unreliablemsg_splitpoints)
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)
1463 msg->maxsize = 1400;
1466 for (numsegments = 0;numsegments < client->unreliablemsg_splitpoints;numsegments++)
1467 if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > msg->maxsize)
1469 if (numsegments > 0)
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;
1490 =======================
1491 SV_SendClientDatagram
1492 =======================
1494 static void SV_SendClientDatagram (client_t *client)
1496 int clientrate, maxrate, maxsize, maxsize2, downloadsize;
1498 int stats[MAX_CL_STATS];
1499 unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE];
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);
1509 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
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);
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)
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
1526 // DP5 and later protocols support packet size limiting which is a
1527 // better method than limiting packet frequency as QW does
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);
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)
1541 msg.data = sv_sendclientdatagram_buf;
1542 msg.maxsize = maxsize;
1545 // obey rate limit by limiting packet frequency if the packet size
1547 // (usually this is caused by reliable messages)
1548 if (!NetConn_CanSend(client->netconnection))
1550 // send the datagram
1551 //NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
1554 else if (host_client->spawned)
1556 MSG_WriteByte (&msg, svc_time);
1557 MSG_WriteFloat (&msg, sv.time);
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);
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);
1572 msg.maxsize = maxsize;
1574 // now write as many entities as we can fit, and also sends stats
1575 SV_WriteEntitiesToClient (client, client->edict, &msg);
1577 else if (realtime > client->keepalivetime)
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);
1586 msg.maxsize = maxsize2;
1588 // if a download is active, see if there is room to fit some download data
1590 downloadsize = maxsize * 2 - msg.cursize - 7;
1591 if (host_client->download_file && host_client->download_started && downloadsize > 0)
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
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);
1611 // send the datagram
1612 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
1616 =======================
1617 SV_UpdateToReliableMessages
1618 =======================
1620 static void SV_UpdateToReliableMessages (void)
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++)
1632 // update the host_client fields we care about according to the entity fields
1633 host_client->edict = PRVM_EDICT_NUM(i+1);
1636 name = PRVM_GetString(host_client->edict->fields.server->netname);
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))
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);
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)
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);
1666 // NEXUIZ_PLAYERMODEL
1667 if( prog->fieldoffsets.playermodel >= 0 ) {
1668 model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
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);
1676 // NEXUIZ_PLAYERSKIN
1677 if( prog->fieldoffsets.playerskin >= 0 ) {
1678 skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
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);
1687 host_client->frags = (int)host_client->edict->fields.server->frags;
1688 if (host_client->old_frags != host_client->frags)
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);
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);
1702 SZ_Clear (&sv.reliable_datagram);
1707 =======================
1708 SV_SendClientMessages
1709 =======================
1711 void SV_SendClientMessages (void)
1715 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1716 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1718 SV_FlushBroadcastMessages();
1720 // update frags, names, etc
1721 SV_UpdateToReliableMessages();
1723 // build individual updates
1724 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1726 if (!host_client->active)
1728 if (!host_client->netconnection)
1731 if (host_client->netconnection->message.overflowed)
1733 SV_DropClient (true); // if the message couldn't send, kick off
1737 SV_SendClientDatagram (host_client);
1740 // clear muzzle flashes
1744 static void SV_StartDownload_f(void)
1746 if (host_client->download_file)
1747 host_client->download_started = true;
1750 static void SV_Download_f(void)
1752 const char *whichpack, *whichpack2, *extension;
1754 if (Cmd_Argc() != 2)
1756 SV_ClientPrintf("usage: download <filename>\n");
1760 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1762 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1766 if (host_client->download_file)
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");
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;
1780 if (!sv_allowdownloads.integer)
1782 SV_ClientPrintf("Downloads are disabled on this server\n");
1783 Host_ClientCommands("\nstopdownload\n");
1787 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1788 extension = FS_FileExtension(host_client->download_name);
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);
1794 if (!FS_FileExists(host_client->download_name))
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");
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))
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");
1811 // check if the server has forbidden archive downloads entirely
1812 if (!sv_allowdownloads_inarchive.integer)
1814 whichpack = FS_WhichPack(host_client->download_name);
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");
1823 if (!sv_allowdownloads_config.integer)
1825 if (!strcasecmp(extension, "cfg"))
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");
1833 if (!sv_allowdownloads_dlcache.integer)
1835 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
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");
1843 if (!sv_allowdownloads_archive.integer)
1845 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
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");
1853 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1854 if (!host_client->download_file)
1856 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1857 Host_ClientCommands("\nstopdownload\n");
1861 if (FS_FileSize(host_client->download_file) > 1<<30)
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;
1870 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1872 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1874 host_client->download_expectedposition = 0;
1875 host_client->download_started = false;
1877 // the rest of the download process is handled in SV_SendClientDatagram
1878 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1880 // no svc_downloaddata messages will be sent until sv_startdownload is
1881 // sent by the client
1885 ==============================================================================
1889 ==============================================================================
1898 int SV_ModelIndex(const char *s, int precachemode)
1900 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1901 char filename[MAX_QPATH];
1905 //if (precachemode == 2)
1907 strlcpy(filename, s, sizeof(filename));
1908 for (i = 2;i < limit;i++)
1910 if (!sv.model_precache[i][0])
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))
1916 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
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)
1925 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1926 MSG_WriteShort(&sv.reliable_datagram, i);
1927 MSG_WriteString(&sv.reliable_datagram, filename);
1931 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1934 if (!strcmp(sv.model_precache[i], filename))
1937 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1947 int SV_SoundIndex(const char *s, int precachemode)
1949 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1950 char filename[MAX_QPATH];
1954 //if (precachemode == 2)
1956 strlcpy(filename, s, sizeof(filename));
1957 for (i = 1;i < limit;i++)
1959 if (!sv.sound_precache[i][0])
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))
1965 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
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)
1973 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1974 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1975 MSG_WriteString(&sv.reliable_datagram, filename);
1979 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1982 if (!strcmp(sv.sound_precache[i], filename))
1985 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1991 SV_ParticleEffectIndex
1995 int SV_ParticleEffectIndex(const char *name)
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)
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);
2011 textstart = (const char *)filedata;
2012 textend = (const char *)filedata + filesize;
2014 for (linenumber = 1;;linenumber++)
2019 if (!COM_ParseToken_Simple(&text, true) || !strcmp(com_token, "\n"))
2023 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
2027 if (com_token[0] == 0)
2028 break; // if the loop exited and it's not a \n, it's EOF
2031 if (!strcmp(argv[0], "effect"))
2035 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
2037 if (sv.particleeffectname[effectnameindex][0])
2039 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
2044 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
2048 // if we run out of names, abort
2049 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
2051 Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
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
2074 static void SV_CreateBaseline (void)
2076 int i, entnum, large;
2077 prvm_edict_t *svent;
2079 // LordHavoc: clear *all* states (note just active ones)
2080 for (entnum = 0;entnum < prog->max_edicts;entnum++)
2082 // get the current server version
2083 svent = PRVM_EDICT_NUM(entnum);
2085 // LordHavoc: always clear state values, whether the entity is in use or not
2086 svent->priv.server->baseline = defaultstate;
2088 if (svent->priv.server->free)
2090 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
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)
2100 svent->priv.server->baseline.colormap = entnum;
2101 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
2105 svent->priv.server->baseline.colormap = 0;
2106 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
2110 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
2113 // add to the message
2115 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
2117 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
2118 MSG_WriteShort (&sv.signon, entnum);
2122 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
2123 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
2127 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
2128 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
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++)
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);
2145 Grabs the current state of each client for saving across the
2146 transition to another level
2149 void SV_SaveSpawnparms (void)
2153 svs.serverflags = (int)prog->globals.server->serverflags;
2155 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2157 if (!host_client->active)
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];
2172 This is called at the start of each level
2176 void SV_SpawnServer (const char *server)
2181 model_t *worldmodel;
2182 char modelname[sizeof(sv.modelname)];
2184 Con_DPrintf("SpawnServer: %s\n", server);
2186 if (cls.state != ca_dedicated)
2187 SCR_BeginLoadingPlaque();
2189 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2190 worldmodel = Mod_ForName(modelname, false, true, true);
2191 if (!worldmodel || !worldmodel->TraceBox)
2193 Con_Printf("Couldn't load map %s\n", modelname);
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;
2202 svs.changelevel_issued = false; // now safe to issue another
2204 // make the map a required file for clients
2205 Curl_ClearRequirements();
2206 Curl_RequireFile(modelname);
2209 // tell all connected clients that we are going to a new level
2214 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2216 if (client->netconnection)
2218 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2219 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2226 NetConn_OpenServerPorts(true);
2230 // make cvars consistant
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);
2240 // set up the new server
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
2247 if(*sv_random_seed.string)
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);
2257 strlcpy (sv.name, server, sizeof (sv.name));
2259 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2260 if (sv.protocol == PROTOCOL_UNKNOWN)
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;
2270 // load progs to get entity field count
2271 //PR_LoadProgs ( sv_progs.string );
2273 sv.datagram.maxsize = sizeof(sv.datagram_buf);
2274 sv.datagram.cursize = 0;
2275 sv.datagram.data = sv.datagram_buf;
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;
2281 sv.signon.maxsize = sizeof(sv.signon_buf);
2282 sv.signon.cursize = 0;
2283 sv.signon.data = sv.signon_buf;
2285 // leave slots at start for clients only
2286 //prog->num_edicts = svs.maxclients+1;
2288 sv.state = ss_loading;
2289 prog->allowworldwrites = true;
2292 prog->globals.server->time = sv.time = 1.0;
2295 worldmodel->used = true;
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;
2303 // clear world interaction links
2305 VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2306 VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2307 World_Clear(&sv.world);
2309 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
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++)
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);
2320 // load the rest of the entities
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);
2336 prog->globals.server->coop = coop.integer;
2338 prog->globals.server->deathmatch = deathmatch.integer;
2340 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2342 // serverflags are for cross level information (sigils)
2343 prog->globals.server->serverflags = svs.serverflags;
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++)
2351 host_client->spawned = false;
2352 host_client->edict = PRVM_EDICT_NUM(i + 1);
2353 PRVM_ED_ClearEdict(host_client->edict);
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)))
2359 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2360 PRVM_ED_LoadFromFile (entities);
2364 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2367 // LordHavoc: clear world angles (to fix e3m3.bsp)
2368 VectorClear(prog->edicts->fields.server->angles);
2370 // all setup is completed, any further precache statements are errors
2371 sv.state = ss_active;
2372 prog->allowworldwrites = false;
2374 // run two frames to allow everything to settle
2375 for (i = 0;i < 2;i++)
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 ();
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++)
2390 if (!host_client->active)
2392 if (host_client->netconnection)
2393 SV_SendServerinfo(host_client);
2397 // if client is a botclient coming from a level change, we need to
2398 // set up client info that normally requires networking
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];
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;
2414 Con_DPrint("Server spawned.\n");
2415 NetConn_Heartbeat (2);
2420 /////////////////////////////////////////////////////
2423 static void SV_VM_CB_BeginIncreaseEdicts(void)
2428 // links don't survive the transition, so unlink everything
2429 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2431 if (!ent->priv.server->free)
2432 World_UnlinkEdict(prog->edicts + i);
2433 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2435 World_Clear(&sv.world);
2438 static void SV_VM_CB_EndIncreaseEdicts(void)
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);
2449 static void SV_VM_CB_InitEdict(prvm_edict_t *e)
2451 // LordHavoc: for consistency set these here
2452 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2454 e->priv.server->move = false; // don't move on first frame
2456 if (num >= 0 && num < svs.maxclients)
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
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);
2484 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString("null/botclient");
2489 static void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2491 World_UnlinkEdict(ed); // unlink from world bsp
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;
2505 static void SV_VM_CB_CountEdicts(void)
2509 int active, models, solid, step;
2511 active = models = solid = step = 0;
2512 for (i=0 ; i<prog->num_edicts ; i++)
2514 ent = PRVM_EDICT_NUM(i);
2515 if (ent->priv.server->free)
2518 if (ent->fields.server->solid)
2520 if (ent->fields.server->model)
2522 if (ent->fields.server->movetype == MOVETYPE_STEP)
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);
2533 static qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2535 // remove things from different skill levels or deathmatch
2536 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2538 if (deathmatch.integer)
2540 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
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 )))
2555 static void SV_VM_Setup(void)
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;
2562 PRVM_InitProg( PRVM_SERVERPROG );
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;
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;
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 );
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;
2620 VM_CustomStats_Clear();//[515]: csqc
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)
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);
2635 void SV_VM_Begin(void)
2638 PRVM_SetProg( PRVM_SERVERPROG );
2640 prog->globals.server->time = (float) sv.time;
2643 void SV_VM_End(void)