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