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