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