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