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