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