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