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