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