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