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