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