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