2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // sv_main.c -- server main program
28 static void SV_SaveEntFile_f(cmd_state_t *cmd);
29 static void SV_StartDownload_f(cmd_state_t *cmd);
30 static void SV_Download_f(cmd_state_t *cmd);
31 static void SV_VM_Setup(void);
32 extern cvar_t net_connecttimeout;
34 cvar_t sv_worldmessage = {CVAR_SERVER | CVAR_READONLY, "sv_worldmessage", "", "title of current level"};
35 cvar_t sv_worldname = {CVAR_SERVER | CVAR_READONLY, "sv_worldname", "", "name of current worldmodel"};
36 cvar_t sv_worldnamenoextension = {CVAR_SERVER | CVAR_READONLY, "sv_worldnamenoextension", "", "name of current worldmodel without extension"};
37 cvar_t sv_worldbasename = {CVAR_SERVER | CVAR_READONLY, "sv_worldbasename", "", "name of current worldmodel without maps/ prefix or extension"};
39 cvar_t sv_disablenotify = {CVAR_SERVER, "sv_disablenotify", "0", "suppress broadcast prints when certain cvars are changed (CVAR_NOTIFY flag in engine code)"};
40 cvar_t coop = {CVAR_SERVER, "coop","0", "coop mode, 0 = no coop, 1 = coop mode, multiple players playing through the singleplayer game (coop mode also shuts off deathmatch)"};
41 cvar_t deathmatch = {CVAR_SERVER, "deathmatch","0", "deathmatch mode, values depend on mod but typically 0 = no deathmatch, 1 = normal deathmatch with respawning weapons, 2 = weapons stay (players can only pick up new weapons)"};
42 cvar_t fraglimit = {CVAR_SERVER | CVAR_NOTIFY, "fraglimit","0", "ends level if this many frags is reached by any player"};
43 cvar_t gamecfg = {CVAR_SERVER, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
44 cvar_t noexit = {CVAR_SERVER | CVAR_NOTIFY, "noexit","0", "kills anyone attempting to use an exit"};
45 cvar_t nomonsters = {CVAR_SERVER, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
46 cvar_t pausable = {CVAR_SERVER, "pausable","1", "allow players to pause or not (otherwise, only the server admin can)"};
47 cvar_t pr_checkextension = {CVAR_SERVER | CVAR_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"};
48 cvar_t samelevel = {CVAR_SERVER | CVAR_NOTIFY, "samelevel","0", "repeats same level if level ends (due to timelimit or someone hitting an exit)"};
49 cvar_t skill = {CVAR_SERVER, "skill","1", "difficulty level of game, affects monster layouts in levels, 0 = easy, 1 = normal, 2 = hard, 3 = nightmare (same layout as hard but monsters fire twice)"};
50 cvar_t host_timescale = {CVAR_CLIENT | CVAR_SERVER, "host_timescale", "1.0", "controls game speed, 0.5 is half speed, 2 is double speed"};
52 cvar_t sv_accelerate = {CVAR_SERVER, "sv_accelerate", "10", "rate at which a player accelerates to sv_maxspeed"};
53 cvar_t sv_aim = {CVAR_SERVER | CVAR_SAVE, "sv_aim", "2", "maximum cosine angle for quake's vertical autoaim, a value above 1 completely disables the autoaim, quake used 0.93"};
54 cvar_t sv_airaccel_qw = {CVAR_SERVER, "sv_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration; when < 0, the speed is clamped against the maximum allowed forward speed after the move"};
55 cvar_t sv_airaccel_qw_stretchfactor = {CVAR_SERVER, "sv_airaccel_qw_stretchfactor", "0", "when set, the maximum acceleration increase the player may get compared to forward-acceleration when strafejumping"};
56 cvar_t sv_airaccel_sideways_friction = {CVAR_SERVER, "sv_airaccel_sideways_friction", "", "anti-sideways movement stabilization (reduces speed gain when zigzagging); when < 0, only so much friction is applied that braking (by accelerating backwards) cannot be stronger"};
57 cvar_t sv_airaccelerate = {CVAR_SERVER, "sv_airaccelerate", "-1", "rate at which a player accelerates to sv_maxairspeed while in the air, if less than 0 the sv_accelerate variable is used instead"};
58 cvar_t sv_airstopaccelerate = {CVAR_SERVER, "sv_airstopaccelerate", "0", "when set, replacement for sv_airaccelerate when moving backwards"};
59 cvar_t sv_airspeedlimit_nonqw = {CVAR_SERVER, "sv_airspeedlimit_nonqw", "0", "when set, this is a soft speed limit while in air when using airaccel_qw not equal to 1"};
60 cvar_t sv_airstrafeaccelerate = {CVAR_SERVER, "sv_airstrafeaccelerate", "0", "when set, replacement for sv_airaccelerate when just strafing"};
61 cvar_t sv_maxairstrafespeed = {CVAR_SERVER, "sv_maxairstrafespeed", "0", "when set, replacement for sv_maxairspeed when just strafing"};
62 cvar_t sv_airstrafeaccel_qw = {CVAR_SERVER, "sv_airstrafeaccel_qw", "0", "when set, replacement for sv_airaccel_qw when just strafing"};
63 cvar_t sv_aircontrol = {CVAR_SERVER, "sv_aircontrol", "0", "CPMA-style air control"};
64 cvar_t sv_aircontrol_power = {CVAR_SERVER, "sv_aircontrol_power", "2", "CPMA-style air control exponent"};
65 cvar_t sv_aircontrol_penalty = {CVAR_SERVER, "sv_aircontrol_penalty", "0", "deceleration while using CPMA-style air control"};
66 cvar_t sv_allowdownloads = {CVAR_SERVER, "sv_allowdownloads", "1", "whether to allow clients to download files from the server (does not affect http downloads)"};
67 cvar_t sv_allowdownloads_archive = {CVAR_SERVER, "sv_allowdownloads_archive", "0", "whether to allow downloads of archives (pak/pk3)"};
68 cvar_t sv_allowdownloads_config = {CVAR_SERVER, "sv_allowdownloads_config", "0", "whether to allow downloads of config files (cfg)"};
69 cvar_t sv_allowdownloads_dlcache = {CVAR_SERVER, "sv_allowdownloads_dlcache", "0", "whether to allow downloads of dlcache files (dlcache/)"};
70 cvar_t sv_allowdownloads_inarchive = {CVAR_SERVER, "sv_allowdownloads_inarchive", "0", "whether to allow downloads from archives (pak/pk3)"};
71 cvar_t sv_areagrid_mingridsize = {CVAR_SERVER | CVAR_NOTIFY, "sv_areagrid_mingridsize", "128", "minimum areagrid cell size, smaller values work better for lots of small objects, higher values for large objects"};
72 cvar_t sv_checkforpacketsduringsleep = {CVAR_SERVER, "sv_checkforpacketsduringsleep", "0", "uses select() function to wait between frames which can be interrupted by packets being received, instead of Sleep()/usleep()/SDL_Sleep() functions which do not check for packets"};
73 cvar_t sv_clmovement_enable = {CVAR_SERVER, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"};
74 cvar_t sv_clmovement_minping = {CVAR_SERVER, "sv_clmovement_minping", "0", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"};
75 cvar_t sv_clmovement_minping_disabletime = {CVAR_SERVER, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"};
76 cvar_t sv_clmovement_inputtimeout = {CVAR_SERVER, "sv_clmovement_inputtimeout", "0.2", "when a client does not send input for this many seconds, force them to move anyway (unlike QuakeWorld)"};
77 cvar_t sv_cullentities_nevercullbmodels = {CVAR_SERVER, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"};
78 cvar_t sv_cullentities_pvs = {CVAR_SERVER, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"};
79 cvar_t sv_cullentities_stats = {CVAR_SERVER, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
80 cvar_t sv_cullentities_trace = {CVAR_SERVER, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"};
81 cvar_t sv_cullentities_trace_delay = {CVAR_SERVER, "sv_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
82 cvar_t sv_cullentities_trace_delay_players = {CVAR_SERVER, "sv_cullentities_trace_delay_players", "0.2", "number of seconds until the entity gets actually culled if it is a player entity"};
83 cvar_t sv_cullentities_trace_enlarge = {CVAR_SERVER, "sv_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
84 cvar_t sv_cullentities_trace_expand = {CVAR_SERVER, "sv_cullentities_trace_expand", "0", "box is expanded by this many units for entity culling"};
85 cvar_t sv_cullentities_trace_eyejitter = {CVAR_SERVER, "sv_cullentities_trace_eyejitter", "16", "jitter the eye by this much for each trace"};
86 cvar_t sv_cullentities_trace_prediction = {CVAR_SERVER, "sv_cullentities_trace_prediction", "1", "also trace from the predicted player position"};
87 cvar_t sv_cullentities_trace_prediction_time = {CVAR_SERVER, "sv_cullentities_trace_prediction_time", "0.2", "how many seconds of prediction to use"};
88 cvar_t sv_cullentities_trace_entityocclusion = {CVAR_SERVER, "sv_cullentities_trace_entityocclusion", "0", "also check if doors and other bsp models are in the way"};
89 cvar_t sv_cullentities_trace_samples = {CVAR_SERVER, "sv_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
90 cvar_t sv_cullentities_trace_samples_extra = {CVAR_SERVER, "sv_cullentities_trace_samples_extra", "2", "number of samples to test for entity culling when the entity affects its surroundings by e.g. dlight"};
91 cvar_t sv_cullentities_trace_samples_players = {CVAR_SERVER, "sv_cullentities_trace_samples_players", "8", "number of samples to test for entity culling when the entity is a player entity"};
92 cvar_t sv_debugmove = {CVAR_SERVER | CVAR_NOTIFY, "sv_debugmove", "0", "disables collision detection optimizations for debugging purposes"};
93 cvar_t sv_echobprint = {CVAR_SERVER | CVAR_SAVE, "sv_echobprint", "1", "prints gamecode bprint() calls to server console"};
94 cvar_t sv_edgefriction = {CVAR_SERVER, "edgefriction", "1", "how much you slow down when nearing a ledge you might fall off, multiplier of sv_friction (Quake used 2, QuakeWorld used 1 due to a bug in physics code)"};
95 cvar_t sv_entpatch = {CVAR_SERVER, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"};
96 cvar_t sv_fixedframeratesingleplayer = {CVAR_SERVER, "sv_fixedframeratesingleplayer", "1", "allows you to use server-style timing system in singleplayer (don't run faster than sys_ticrate)"};
97 cvar_t sv_freezenonclients = {CVAR_SERVER | CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"};
98 cvar_t sv_friction = {CVAR_SERVER | CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"};
99 cvar_t sv_gameplayfix_blowupfallenzombies = {CVAR_SERVER, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
100 cvar_t sv_gameplayfix_consistentplayerprethink = {CVAR_SERVER, "sv_gameplayfix_consistentplayerprethink", "0", "improves fairness in multiplayer by running all PlayerPreThink functions (which fire weapons) before performing physics, then running all PlayerPostThink functions"};
101 cvar_t sv_gameplayfix_delayprojectiles = {CVAR_SERVER, "sv_gameplayfix_delayprojectiles", "1", "causes entities to not move on the same frame they are spawned, meaning that projectiles wait until the next frame to perform their first move, giving proper interpolation and rocket trails, but making weapons harder to use at low framerates"};
102 cvar_t sv_gameplayfix_droptofloorstartsolid = {CVAR_SERVER, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
103 cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect = {CVAR_SERVER, "sv_gameplayfix_droptofloorstartsolid_nudgetocorrect", "1", "tries to nudge stuck items and monsters out of walls before droptofloor is performed"};
104 cvar_t sv_gameplayfix_easierwaterjump = {CVAR_SERVER, "sv_gameplayfix_easierwaterjump", "1", "changes water jumping to make it easier to get out of water (exactly like in QuakeWorld)"};
105 cvar_t sv_gameplayfix_findradiusdistancetobox = {CVAR_SERVER, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"};
106 cvar_t sv_gameplayfix_gravityunaffectedbyticrate = {CVAR_SERVER, "sv_gameplayfix_gravityunaffectedbyticrate", "0", "fix some ticrate issues in physics."};
107 cvar_t sv_gameplayfix_grenadebouncedownslopes = {CVAR_SERVER, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
108 cvar_t sv_gameplayfix_multiplethinksperframe = {CVAR_SERVER, "sv_gameplayfix_multiplethinksperframe", "1", "allows entities to think more often than the server framerate, primarily useful for very high fire rate weapons"};
109 cvar_t sv_gameplayfix_noairborncorpse = {CVAR_SERVER, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses, items, etc) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
110 cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems = {CVAR_SERVER, "sv_gameplayfix_noairborncorpse_allowsuspendeditems", "1", "causes entities sitting ontop of objects that are instantaneously remove to float in midair (special hack to allow a common level design trick for floating items)"};
111 cvar_t sv_gameplayfix_nudgeoutofsolid = {CVAR_SERVER, "sv_gameplayfix_nudgeoutofsolid", "0", "attempts to fix physics errors (where an object ended up in solid for some reason)"};
112 cvar_t sv_gameplayfix_nudgeoutofsolid_separation = {CVAR_SERVER, "sv_gameplayfix_nudgeoutofsolid_separation", "0.03125", "keep objects this distance apart to prevent collision issues on seams"};
113 cvar_t sv_gameplayfix_q2airaccelerate = {CVAR_SERVER, "sv_gameplayfix_q2airaccelerate", "0", "Quake2-style air acceleration"};
114 cvar_t sv_gameplayfix_nogravityonground = {CVAR_SERVER, "sv_gameplayfix_nogravityonground", "0", "turn off gravity when on ground (to get rid of sliding)"};
115 cvar_t sv_gameplayfix_setmodelrealbox = {CVAR_SERVER, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
116 cvar_t sv_gameplayfix_slidemoveprojectiles = {CVAR_SERVER, "sv_gameplayfix_slidemoveprojectiles", "1", "allows MOVETYPE_FLY/FLYMISSILE/TOSS/BOUNCE/BOUNCEMISSILE entities to finish their move in a frame even if they hit something, fixes 'gravity accumulation' bug for grenades on steep slopes"};
117 cvar_t sv_gameplayfix_stepdown = {CVAR_SERVER, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"};
118 cvar_t sv_gameplayfix_stepmultipletimes = {CVAR_SERVER, "sv_gameplayfix_stepmultipletimes", "0", "applies step-up onto a ledge more than once in a single frame, when running quickly up stairs"};
119 cvar_t sv_gameplayfix_nostepmoveonsteepslopes = {CVAR_SERVER, "sv_gameplayfix_nostepmoveonsteepslopes", "0", "crude fix which prevents MOVETYPE_STEP (not swimming or flying) to move on slopes whose angle is bigger than 45 degree"};
120 cvar_t sv_gameplayfix_swiminbmodels = {CVAR_SERVER, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
121 cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {CVAR_SERVER, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
122 cvar_t sv_gameplayfix_downtracesupportsongroundflag = {CVAR_SERVER, "sv_gameplayfix_downtracesupportsongroundflag", "1", "prevents very short moves from clearing onground (which may make the player stick to the floor at high netfps)"};
123 cvar_t sv_gameplayfix_q1bsptracelinereportstexture = {CVAR_SERVER, "sv_gameplayfix_q1bsptracelinereportstexture", "1", "enables mods to get accurate trace_texture results on q1bsp by using a surface-hitting traceline implementation rather than the standard solidbsp method, q3bsp always reports texture accurately"};
124 cvar_t sv_gameplayfix_unstickplayers = {CVAR_SERVER, "sv_gameplayfix_unstickplayers", "1", "big hack to try and fix the rare case of MOVETYPE_WALK entities getting stuck in the world clipping hull."};
125 cvar_t sv_gameplayfix_unstickentities = {CVAR_SERVER, "sv_gameplayfix_unstickentities", "1", "hack to check if entities are crossing world collision hull and try to move them to the right position"};
126 cvar_t sv_gameplayfix_fixedcheckwatertransition = {CVAR_SERVER, "sv_gameplayfix_fixedcheckwatertransition", "1", "fix two very stupid bugs in SV_CheckWaterTransition when watertype is CONTENTS_EMPTY (the bugs causes waterlevel to be 1 on first frame, -1 on second frame - the fix makes it 0 on both frames)"};
127 cvar_t sv_gravity = {CVAR_SERVER | CVAR_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"};
128 cvar_t sv_init_frame_count = {CVAR_SERVER, "sv_init_frame_count", "2", "number of frames to run to allow everything to settle before letting clients connect"};
129 cvar_t sv_idealpitchscale = {CVAR_SERVER, "sv_idealpitchscale","0.8", "how much to look up/down slopes and stairs when not using freelook"};
130 cvar_t sv_jumpstep = {CVAR_SERVER | CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping"};
131 cvar_t sv_jumpvelocity = {CVAR_SERVER, "sv_jumpvelocity", "270", "cvar that can be used by QuakeC code for jump velocity"};
132 cvar_t sv_maxairspeed = {CVAR_SERVER, "sv_maxairspeed", "30", "maximum speed a player can accelerate to when airborn (note that it is possible to completely stop by moving the opposite direction)"};
133 cvar_t sv_maxrate = {CVAR_SERVER | CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "1000000", "upper limit on client rate cvar, should reflect your network connection quality"};
134 cvar_t sv_maxspeed = {CVAR_SERVER | CVAR_NOTIFY, "sv_maxspeed", "320", "maximum speed a player can accelerate to when on ground (can be exceeded by tricks)"};
135 cvar_t sv_maxvelocity = {CVAR_SERVER | CVAR_NOTIFY, "sv_maxvelocity","2000", "universal speed limit on all entities"};
136 cvar_t sv_nostep = {CVAR_SERVER | CVAR_NOTIFY, "sv_nostep","0", "prevents MOVETYPE_STEP entities (monsters) from moving"};
137 cvar_t sv_playerphysicsqc = {CVAR_SERVER | CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables QuakeC function to override player physics"};
138 cvar_t sv_progs = {CVAR_SERVER, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
139 cvar_t sv_protocolname = {CVAR_SERVER, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
140 cvar_t sv_random_seed = {CVAR_SERVER, "sv_random_seed", "", "random seed; when set, on every map start this random seed is used to initialize the random number generator. Don't touch it unless for benchmarking or debugging"};
141 cvar_t sv_ratelimitlocalplayer = {CVAR_SERVER, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
142 cvar_t sv_sound_land = {CVAR_SERVER, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"};
143 cvar_t sv_sound_watersplash = {CVAR_SERVER, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"};
144 cvar_t sv_stepheight = {CVAR_SERVER | CVAR_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"};
145 cvar_t sv_stopspeed = {CVAR_SERVER | CVAR_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"};
146 cvar_t sv_wallfriction = {CVAR_SERVER | CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"};
147 cvar_t sv_wateraccelerate = {CVAR_SERVER, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in the air, if less than 0 the sv_accelerate variable is used instead"};
148 cvar_t sv_waterfriction = {CVAR_SERVER | CVAR_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"};
149 cvar_t sv_warsowbunny_airforwardaccel = {CVAR_SERVER, "sv_warsowbunny_airforwardaccel", "1.00001", "how fast you accelerate until you reach sv_maxspeed"};
150 cvar_t sv_warsowbunny_accel = {CVAR_SERVER, "sv_warsowbunny_accel", "0.1585", "how fast you accelerate until after reaching sv_maxspeed (it gets harder as you near sv_warsowbunny_topspeed)"};
151 cvar_t sv_warsowbunny_topspeed = {CVAR_SERVER, "sv_warsowbunny_topspeed", "925", "soft speed limit (can get faster with rjs and on ramps)"};
152 cvar_t sv_warsowbunny_turnaccel = {CVAR_SERVER, "sv_warsowbunny_turnaccel", "0", "max sharpness of turns (also master switch for the sv_warsowbunny_* mode; set this to 9 to enable)"};
153 cvar_t sv_warsowbunny_backtosideratio = {CVAR_SERVER, "sv_warsowbunny_backtosideratio", "0.8", "lower values make it easier to change direction without losing speed; the drawback is \"understeering\" in sharp turns"};
154 cvar_t sv_onlycsqcnetworking = {CVAR_SERVER, "sv_onlycsqcnetworking", "0", "disables legacy entity networking code for higher performance (except on clients, which can still be legacy)"};
155 cvar_t sv_areadebug = {CVAR_SERVER, "sv_areadebug", "0", "disables physics culling for debugging purposes (only for development)"};
156 cvar_t sys_ticrate = {CVAR_SERVER | CVAR_SAVE, "sys_ticrate","0.0138889", "how long a server frame is in seconds, 0.05 is 20fps server rate, 0.1 is 10fps (can not be set higher than 0.1), 0 runs as many server frames as possible (makes games against bots a little smoother, overwhelms network players), 0.0138889 matches QuakeWorld physics"};
157 cvar_t teamplay = {CVAR_SERVER | CVAR_NOTIFY, "teamplay","0", "teamplay mode, values depend on mod but typically 0 = no teams, 1 = no team damage no self damage, 2 = team damage and self damage, some mods support 3 = no team damage but can damage self"};
158 cvar_t timelimit = {CVAR_SERVER | CVAR_NOTIFY, "timelimit","0", "ends level at this time (in minutes)"};
159 cvar_t sv_threaded = {CVAR_SERVER, "sv_threaded", "0", "enables a separate thread for server code, improving performance, especially when hosting a game while playing, EXPERIMENTAL, may be crashy"};
161 cvar_t saved1 = {CVAR_SERVER | CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
162 cvar_t saved2 = {CVAR_SERVER | CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
163 cvar_t saved3 = {CVAR_SERVER | CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
164 cvar_t saved4 = {CVAR_SERVER | CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
165 cvar_t savedgamecfg = {CVAR_SERVER | CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
166 cvar_t scratch1 = {CVAR_SERVER, "scratch1", "0", "unused cvar in quake, can be used by mods"};
167 cvar_t scratch2 = {CVAR_SERVER,"scratch2", "0", "unused cvar in quake, can be used by mods"};
168 cvar_t scratch3 = {CVAR_SERVER, "scratch3", "0", "unused cvar in quake, can be used by mods"};
169 cvar_t scratch4 = {CVAR_SERVER, "scratch4", "0", "unused cvar in quake, can be used by mods"};
170 cvar_t temp1 = {CVAR_SERVER, "temp1","0", "general cvar for mods to use, in stock id1 this selects which death animation to use on players (0 = random death, other values select specific death scenes)"};
172 cvar_t nehx00 = {CVAR_SERVER, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
173 cvar_t nehx01 = {CVAR_SERVER, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
174 cvar_t nehx02 = {CVAR_SERVER, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
175 cvar_t nehx03 = {CVAR_SERVER, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
176 cvar_t nehx04 = {CVAR_SERVER, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
177 cvar_t nehx05 = {CVAR_SERVER, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
178 cvar_t nehx06 = {CVAR_SERVER, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
179 cvar_t nehx07 = {CVAR_SERVER, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
180 cvar_t nehx08 = {CVAR_SERVER, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
181 cvar_t nehx09 = {CVAR_SERVER, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
182 cvar_t nehx10 = {CVAR_SERVER, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
183 cvar_t nehx11 = {CVAR_SERVER, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
184 cvar_t nehx12 = {CVAR_SERVER, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
185 cvar_t nehx13 = {CVAR_SERVER, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
186 cvar_t nehx14 = {CVAR_SERVER, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
187 cvar_t nehx15 = {CVAR_SERVER, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
188 cvar_t nehx16 = {CVAR_SERVER, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
189 cvar_t nehx17 = {CVAR_SERVER, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
190 cvar_t nehx18 = {CVAR_SERVER, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
191 cvar_t nehx19 = {CVAR_SERVER, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
192 cvar_t cutscene = {CVAR_SERVER, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
194 cvar_t sv_autodemo_perclient = {CVAR_SERVER | CVAR_SAVE, "sv_autodemo_perclient", "0", "set to 1 to enable autorecorded per-client demos (they'll start to record at the beginning of a match); set it to 2 to also record client->server packets (for debugging)"};
195 cvar_t sv_autodemo_perclient_nameformat = {CVAR_SERVER | CVAR_SAVE, "sv_autodemo_perclient_nameformat", "sv_autodemos/%Y-%m-%d_%H-%M", "The format of the sv_autodemo_perclient filename, followed by the map name, the client number and the IP address + port number, separated by underscores (the date is encoded using strftime escapes)" };
196 cvar_t sv_autodemo_perclient_discardable = {CVAR_SERVER | CVAR_SAVE, "sv_autodemo_perclient_discardable", "0", "Allow game code to decide whether a demo should be kept or discarded."};
198 cvar_t halflifebsp = {CVAR_SERVER, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"};
199 cvar_t sv_mapformat_is_quake2 = {CVAR_SERVER, "sv_mapformat_is_quake2", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors, .frame on submodels and other things)"};
200 cvar_t sv_mapformat_is_quake3 = {CVAR_SERVER, "sv_mapformat_is_quake3", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors)"};
205 mempool_t *sv_mempool = NULL;
207 extern cvar_t host_timescale;
208 extern float scr_centertime_off;
210 // MUST match effectnameindex_t in client.h
211 static const char *standardeffectnames[EFFECT_TOTAL] =
235 "TE_TEI_BIGEXPLOSION",
251 #define SV_REQFUNCS 0
252 #define sv_reqfuncs NULL
254 //#define SV_REQFUNCS (sizeof(sv_reqfuncs) / sizeof(const char *))
255 //static const char *sv_reqfuncs[] = {
258 #define SV_REQFIELDS (sizeof(sv_reqfields) / sizeof(prvm_required_field_t))
260 prvm_required_field_t sv_reqfields[] =
262 #define PRVM_DECLARE_serverglobalfloat(x)
263 #define PRVM_DECLARE_serverglobalvector(x)
264 #define PRVM_DECLARE_serverglobalstring(x)
265 #define PRVM_DECLARE_serverglobaledict(x)
266 #define PRVM_DECLARE_serverglobalfunction(x)
267 #define PRVM_DECLARE_clientglobalfloat(x)
268 #define PRVM_DECLARE_clientglobalvector(x)
269 #define PRVM_DECLARE_clientglobalstring(x)
270 #define PRVM_DECLARE_clientglobaledict(x)
271 #define PRVM_DECLARE_clientglobalfunction(x)
272 #define PRVM_DECLARE_menuglobalfloat(x)
273 #define PRVM_DECLARE_menuglobalvector(x)
274 #define PRVM_DECLARE_menuglobalstring(x)
275 #define PRVM_DECLARE_menuglobaledict(x)
276 #define PRVM_DECLARE_menuglobalfunction(x)
277 #define PRVM_DECLARE_serverfieldfloat(x) {ev_float, #x},
278 #define PRVM_DECLARE_serverfieldvector(x) {ev_vector, #x},
279 #define PRVM_DECLARE_serverfieldstring(x) {ev_string, #x},
280 #define PRVM_DECLARE_serverfieldedict(x) {ev_entity, #x},
281 #define PRVM_DECLARE_serverfieldfunction(x) {ev_function, #x},
282 #define PRVM_DECLARE_clientfieldfloat(x)
283 #define PRVM_DECLARE_clientfieldvector(x)
284 #define PRVM_DECLARE_clientfieldstring(x)
285 #define PRVM_DECLARE_clientfieldedict(x)
286 #define PRVM_DECLARE_clientfieldfunction(x)
287 #define PRVM_DECLARE_menufieldfloat(x)
288 #define PRVM_DECLARE_menufieldvector(x)
289 #define PRVM_DECLARE_menufieldstring(x)
290 #define PRVM_DECLARE_menufieldedict(x)
291 #define PRVM_DECLARE_menufieldfunction(x)
292 #define PRVM_DECLARE_serverfunction(x)
293 #define PRVM_DECLARE_clientfunction(x)
294 #define PRVM_DECLARE_menufunction(x)
295 #define PRVM_DECLARE_field(x)
296 #define PRVM_DECLARE_global(x)
297 #define PRVM_DECLARE_function(x)
298 #include "prvm_offsets.h"
299 #undef PRVM_DECLARE_serverglobalfloat
300 #undef PRVM_DECLARE_serverglobalvector
301 #undef PRVM_DECLARE_serverglobalstring
302 #undef PRVM_DECLARE_serverglobaledict
303 #undef PRVM_DECLARE_serverglobalfunction
304 #undef PRVM_DECLARE_clientglobalfloat
305 #undef PRVM_DECLARE_clientglobalvector
306 #undef PRVM_DECLARE_clientglobalstring
307 #undef PRVM_DECLARE_clientglobaledict
308 #undef PRVM_DECLARE_clientglobalfunction
309 #undef PRVM_DECLARE_menuglobalfloat
310 #undef PRVM_DECLARE_menuglobalvector
311 #undef PRVM_DECLARE_menuglobalstring
312 #undef PRVM_DECLARE_menuglobaledict
313 #undef PRVM_DECLARE_menuglobalfunction
314 #undef PRVM_DECLARE_serverfieldfloat
315 #undef PRVM_DECLARE_serverfieldvector
316 #undef PRVM_DECLARE_serverfieldstring
317 #undef PRVM_DECLARE_serverfieldedict
318 #undef PRVM_DECLARE_serverfieldfunction
319 #undef PRVM_DECLARE_clientfieldfloat
320 #undef PRVM_DECLARE_clientfieldvector
321 #undef PRVM_DECLARE_clientfieldstring
322 #undef PRVM_DECLARE_clientfieldedict
323 #undef PRVM_DECLARE_clientfieldfunction
324 #undef PRVM_DECLARE_menufieldfloat
325 #undef PRVM_DECLARE_menufieldvector
326 #undef PRVM_DECLARE_menufieldstring
327 #undef PRVM_DECLARE_menufieldedict
328 #undef PRVM_DECLARE_menufieldfunction
329 #undef PRVM_DECLARE_serverfunction
330 #undef PRVM_DECLARE_clientfunction
331 #undef PRVM_DECLARE_menufunction
332 #undef PRVM_DECLARE_field
333 #undef PRVM_DECLARE_global
334 #undef PRVM_DECLARE_function
337 #define SV_REQGLOBALS (sizeof(sv_reqglobals) / sizeof(prvm_required_field_t))
339 prvm_required_field_t sv_reqglobals[] =
341 #define PRVM_DECLARE_serverglobalfloat(x) {ev_float, #x},
342 #define PRVM_DECLARE_serverglobalvector(x) {ev_vector, #x},
343 #define PRVM_DECLARE_serverglobalstring(x) {ev_string, #x},
344 #define PRVM_DECLARE_serverglobaledict(x) {ev_entity, #x},
345 #define PRVM_DECLARE_serverglobalfunction(x) {ev_function, #x},
346 #define PRVM_DECLARE_clientglobalfloat(x)
347 #define PRVM_DECLARE_clientglobalvector(x)
348 #define PRVM_DECLARE_clientglobalstring(x)
349 #define PRVM_DECLARE_clientglobaledict(x)
350 #define PRVM_DECLARE_clientglobalfunction(x)
351 #define PRVM_DECLARE_menuglobalfloat(x)
352 #define PRVM_DECLARE_menuglobalvector(x)
353 #define PRVM_DECLARE_menuglobalstring(x)
354 #define PRVM_DECLARE_menuglobaledict(x)
355 #define PRVM_DECLARE_menuglobalfunction(x)
356 #define PRVM_DECLARE_serverfieldfloat(x)
357 #define PRVM_DECLARE_serverfieldvector(x)
358 #define PRVM_DECLARE_serverfieldstring(x)
359 #define PRVM_DECLARE_serverfieldedict(x)
360 #define PRVM_DECLARE_serverfieldfunction(x)
361 #define PRVM_DECLARE_clientfieldfloat(x)
362 #define PRVM_DECLARE_clientfieldvector(x)
363 #define PRVM_DECLARE_clientfieldstring(x)
364 #define PRVM_DECLARE_clientfieldedict(x)
365 #define PRVM_DECLARE_clientfieldfunction(x)
366 #define PRVM_DECLARE_menufieldfloat(x)
367 #define PRVM_DECLARE_menufieldvector(x)
368 #define PRVM_DECLARE_menufieldstring(x)
369 #define PRVM_DECLARE_menufieldedict(x)
370 #define PRVM_DECLARE_menufieldfunction(x)
371 #define PRVM_DECLARE_serverfunction(x)
372 #define PRVM_DECLARE_clientfunction(x)
373 #define PRVM_DECLARE_menufunction(x)
374 #define PRVM_DECLARE_field(x)
375 #define PRVM_DECLARE_global(x)
376 #define PRVM_DECLARE_function(x)
377 #include "prvm_offsets.h"
378 #undef PRVM_DECLARE_serverglobalfloat
379 #undef PRVM_DECLARE_serverglobalvector
380 #undef PRVM_DECLARE_serverglobalstring
381 #undef PRVM_DECLARE_serverglobaledict
382 #undef PRVM_DECLARE_serverglobalfunction
383 #undef PRVM_DECLARE_clientglobalfloat
384 #undef PRVM_DECLARE_clientglobalvector
385 #undef PRVM_DECLARE_clientglobalstring
386 #undef PRVM_DECLARE_clientglobaledict
387 #undef PRVM_DECLARE_clientglobalfunction
388 #undef PRVM_DECLARE_menuglobalfloat
389 #undef PRVM_DECLARE_menuglobalvector
390 #undef PRVM_DECLARE_menuglobalstring
391 #undef PRVM_DECLARE_menuglobaledict
392 #undef PRVM_DECLARE_menuglobalfunction
393 #undef PRVM_DECLARE_serverfieldfloat
394 #undef PRVM_DECLARE_serverfieldvector
395 #undef PRVM_DECLARE_serverfieldstring
396 #undef PRVM_DECLARE_serverfieldedict
397 #undef PRVM_DECLARE_serverfieldfunction
398 #undef PRVM_DECLARE_clientfieldfloat
399 #undef PRVM_DECLARE_clientfieldvector
400 #undef PRVM_DECLARE_clientfieldstring
401 #undef PRVM_DECLARE_clientfieldedict
402 #undef PRVM_DECLARE_clientfieldfunction
403 #undef PRVM_DECLARE_menufieldfloat
404 #undef PRVM_DECLARE_menufieldvector
405 #undef PRVM_DECLARE_menufieldstring
406 #undef PRVM_DECLARE_menufieldedict
407 #undef PRVM_DECLARE_menufieldfunction
408 #undef PRVM_DECLARE_serverfunction
409 #undef PRVM_DECLARE_clientfunction
410 #undef PRVM_DECLARE_menufunction
411 #undef PRVM_DECLARE_field
412 #undef PRVM_DECLARE_global
413 #undef PRVM_DECLARE_function
416 static void Host_Timescale_c(char *string)
419 value = atof(string);
421 if(value < 0.00001 && value != 0)
422 string[0] = '0', string[1] = 0;
425 //============================================================================
427 static void SV_AreaStats_f(cmd_state_t *cmd)
429 World_PrintAreaStats(&sv.world, "server");
439 // init the csqc progs cvars, since they are updated/used by the server code
440 // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
441 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
442 extern cvar_t csqc_progcrc;
443 extern cvar_t csqc_progsize;
444 extern cvar_t csqc_usedemoprogs;
446 Cvar_RegisterVariable(&sv_worldmessage);
447 Cvar_RegisterVariable(&sv_worldname);
448 Cvar_RegisterVariable(&sv_worldnamenoextension);
449 Cvar_RegisterVariable(&sv_worldbasename);
451 Cvar_RegisterVariable (&csqc_progname);
452 Cvar_RegisterVariable (&csqc_progcrc);
453 Cvar_RegisterVariable (&csqc_progsize);
454 Cvar_RegisterVariable (&csqc_usedemoprogs);
456 Cmd_AddCommand(CMD_SHARED, "sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
457 Cmd_AddCommand(CMD_SHARED, "sv_areastats", SV_AreaStats_f, "prints statistics on entity culling during collision traces");
458 Cmd_AddCommand(CMD_CLIENT | CMD_SERVER_FROM_CLIENT, "sv_startdownload", SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
459 Cmd_AddCommand(CMD_CLIENT | CMD_SERVER_FROM_CLIENT, "download", SV_Download_f, "downloads a specified file from the server");
461 Cvar_RegisterVariable (&sv_disablenotify);
462 Cvar_RegisterVariable (&coop);
463 Cvar_RegisterVariable (&deathmatch);
464 Cvar_RegisterVariable (&fraglimit);
465 Cvar_RegisterVariable (&gamecfg);
466 Cvar_RegisterVariable (&noexit);
467 Cvar_RegisterVariable (&nomonsters);
468 Cvar_RegisterVariable (&pausable);
469 Cvar_RegisterVariable (&pr_checkextension);
470 Cvar_RegisterVariable (&samelevel);
471 Cvar_RegisterVariable (&skill);
472 Cvar_RegisterVariable (&host_timescale);
473 Cvar_RegisterCallback (&host_timescale, Host_Timescale_c);
474 Cvar_RegisterAlias (&host_timescale, "slowmo");
475 Cvar_RegisterAlias (&host_timescale, "timescale");
476 Cvar_RegisterVariable (&sv_accelerate);
477 Cvar_RegisterVariable (&sv_aim);
478 Cvar_RegisterVariable (&sv_airaccel_qw);
479 Cvar_RegisterVariable (&sv_airaccel_qw_stretchfactor);
480 Cvar_RegisterVariable (&sv_airaccel_sideways_friction);
481 Cvar_RegisterVariable (&sv_airaccelerate);
482 Cvar_RegisterVariable (&sv_airstopaccelerate);
483 Cvar_RegisterVariable (&sv_airstrafeaccelerate);
484 Cvar_RegisterVariable (&sv_maxairstrafespeed);
485 Cvar_RegisterVariable (&sv_airstrafeaccel_qw);
486 Cvar_RegisterVariable (&sv_airspeedlimit_nonqw);
487 Cvar_RegisterVariable (&sv_aircontrol);
488 Cvar_RegisterVariable (&sv_aircontrol_power);
489 Cvar_RegisterVariable (&sv_aircontrol_penalty);
490 Cvar_RegisterVariable (&sv_allowdownloads);
491 Cvar_RegisterVariable (&sv_allowdownloads_archive);
492 Cvar_RegisterVariable (&sv_allowdownloads_config);
493 Cvar_RegisterVariable (&sv_allowdownloads_dlcache);
494 Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
495 Cvar_RegisterVariable (&sv_areagrid_mingridsize);
496 Cvar_RegisterVariable (&sv_checkforpacketsduringsleep);
497 Cvar_RegisterVariable (&sv_clmovement_enable);
498 Cvar_RegisterVariable (&sv_clmovement_minping);
499 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
500 Cvar_RegisterVariable (&sv_clmovement_inputtimeout);
501 Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels);
502 Cvar_RegisterVariable (&sv_cullentities_pvs);
503 Cvar_RegisterVariable (&sv_cullentities_stats);
504 Cvar_RegisterVariable (&sv_cullentities_trace);
505 Cvar_RegisterVariable (&sv_cullentities_trace_delay);
506 Cvar_RegisterVariable (&sv_cullentities_trace_delay_players);
507 Cvar_RegisterVariable (&sv_cullentities_trace_enlarge);
508 Cvar_RegisterVariable (&sv_cullentities_trace_expand);
509 Cvar_RegisterVariable (&sv_cullentities_trace_eyejitter);
510 Cvar_RegisterVariable (&sv_cullentities_trace_entityocclusion);
511 Cvar_RegisterVariable (&sv_cullentities_trace_prediction);
512 Cvar_RegisterVariable (&sv_cullentities_trace_prediction_time);
513 Cvar_RegisterVariable (&sv_cullentities_trace_samples);
514 Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra);
515 Cvar_RegisterVariable (&sv_cullentities_trace_samples_players);
516 Cvar_RegisterVariable (&sv_debugmove);
517 Cvar_RegisterVariable (&sv_echobprint);
518 Cvar_RegisterVariable (&sv_edgefriction);
519 Cvar_RegisterVariable (&sv_entpatch);
520 Cvar_RegisterVariable (&sv_fixedframeratesingleplayer);
521 Cvar_RegisterVariable (&sv_freezenonclients);
522 Cvar_RegisterVariable (&sv_friction);
523 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
524 Cvar_RegisterVariable (&sv_gameplayfix_consistentplayerprethink);
525 Cvar_RegisterVariable (&sv_gameplayfix_delayprojectiles);
526 Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
527 Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid_nudgetocorrect);
528 Cvar_RegisterVariable (&sv_gameplayfix_easierwaterjump);
529 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
530 Cvar_RegisterVariable (&sv_gameplayfix_gravityunaffectedbyticrate);
531 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
532 Cvar_RegisterVariable (&sv_gameplayfix_multiplethinksperframe);
533 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
534 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse_allowsuspendeditems);
535 Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid);
536 Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid_separation);
537 Cvar_RegisterVariable (&sv_gameplayfix_q2airaccelerate);
538 Cvar_RegisterVariable (&sv_gameplayfix_nogravityonground);
539 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
540 Cvar_RegisterVariable (&sv_gameplayfix_slidemoveprojectiles);
541 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
542 Cvar_RegisterVariable (&sv_gameplayfix_stepmultipletimes);
543 Cvar_RegisterVariable (&sv_gameplayfix_nostepmoveonsteepslopes);
544 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
545 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
546 Cvar_RegisterVariable (&sv_gameplayfix_downtracesupportsongroundflag);
547 Cvar_RegisterVariable (&sv_gameplayfix_q1bsptracelinereportstexture);
548 Cvar_RegisterVariable (&sv_gameplayfix_unstickplayers);
549 Cvar_RegisterVariable (&sv_gameplayfix_unstickentities);
550 Cvar_RegisterVariable (&sv_gameplayfix_fixedcheckwatertransition);
551 Cvar_RegisterVariable (&sv_gravity);
552 Cvar_RegisterVariable (&sv_init_frame_count);
553 Cvar_RegisterVariable (&sv_idealpitchscale);
554 Cvar_RegisterVariable (&sv_jumpstep);
555 Cvar_RegisterVariable (&sv_jumpvelocity);
556 Cvar_RegisterVariable (&sv_maxairspeed);
557 Cvar_RegisterVariable (&sv_maxrate);
558 Cvar_RegisterVariable (&sv_maxspeed);
559 Cvar_RegisterVariable (&sv_maxvelocity);
560 Cvar_RegisterVariable (&sv_nostep);
561 Cvar_RegisterVariable (&sv_playerphysicsqc);
562 Cvar_RegisterVariable (&sv_progs);
563 Cvar_RegisterVariable (&sv_protocolname);
564 Cvar_RegisterVariable (&sv_random_seed);
565 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
566 Cvar_RegisterVariable (&sv_sound_land);
567 Cvar_RegisterVariable (&sv_sound_watersplash);
568 Cvar_RegisterVariable (&sv_stepheight);
569 Cvar_RegisterVariable (&sv_stopspeed);
570 Cvar_RegisterVariable (&sv_wallfriction);
571 Cvar_RegisterVariable (&sv_wateraccelerate);
572 Cvar_RegisterVariable (&sv_waterfriction);
573 Cvar_RegisterVariable (&sv_warsowbunny_airforwardaccel);
574 Cvar_RegisterVariable (&sv_warsowbunny_accel);
575 Cvar_RegisterVariable (&sv_warsowbunny_topspeed);
576 Cvar_RegisterVariable (&sv_warsowbunny_turnaccel);
577 Cvar_RegisterVariable (&sv_warsowbunny_backtosideratio);
578 Cvar_RegisterVariable (&sv_onlycsqcnetworking);
579 Cvar_RegisterVariable (&sv_areadebug);
580 Cvar_RegisterVariable (&sys_ticrate);
581 Cvar_RegisterVariable (&teamplay);
582 Cvar_RegisterVariable (&timelimit);
583 Cvar_RegisterVariable (&sv_threaded);
585 Cvar_RegisterVariable (&saved1);
586 Cvar_RegisterVariable (&saved2);
587 Cvar_RegisterVariable (&saved3);
588 Cvar_RegisterVariable (&saved4);
589 Cvar_RegisterVariable (&savedgamecfg);
590 Cvar_RegisterVariable (&scratch1);
591 Cvar_RegisterVariable (&scratch2);
592 Cvar_RegisterVariable (&scratch3);
593 Cvar_RegisterVariable (&scratch4);
594 Cvar_RegisterVariable (&temp1);
596 // LadyHavoc: Nehahra uses these to pass data around cutscene demos
597 Cvar_RegisterVariable (&nehx00);
598 Cvar_RegisterVariable (&nehx01);
599 Cvar_RegisterVariable (&nehx02);
600 Cvar_RegisterVariable (&nehx03);
601 Cvar_RegisterVariable (&nehx04);
602 Cvar_RegisterVariable (&nehx05);
603 Cvar_RegisterVariable (&nehx06);
604 Cvar_RegisterVariable (&nehx07);
605 Cvar_RegisterVariable (&nehx08);
606 Cvar_RegisterVariable (&nehx09);
607 Cvar_RegisterVariable (&nehx10);
608 Cvar_RegisterVariable (&nehx11);
609 Cvar_RegisterVariable (&nehx12);
610 Cvar_RegisterVariable (&nehx13);
611 Cvar_RegisterVariable (&nehx14);
612 Cvar_RegisterVariable (&nehx15);
613 Cvar_RegisterVariable (&nehx16);
614 Cvar_RegisterVariable (&nehx17);
615 Cvar_RegisterVariable (&nehx18);
616 Cvar_RegisterVariable (&nehx19);
617 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
619 Cvar_RegisterVariable (&sv_autodemo_perclient);
620 Cvar_RegisterVariable (&sv_autodemo_perclient_nameformat);
621 Cvar_RegisterVariable (&sv_autodemo_perclient_discardable);
623 Cvar_RegisterVariable (&halflifebsp);
624 Cvar_RegisterVariable (&sv_mapformat_is_quake2);
625 Cvar_RegisterVariable (&sv_mapformat_is_quake3);
627 sv_mempool = Mem_AllocPool("server", 0, NULL);
630 static void SV_SaveEntFile_f(cmd_state_t *cmd)
633 if (!sv.active || !sv.worldmodel)
635 Con_Print("Not running a server\n");
638 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s.ent", sv.worldnamenoextension), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
643 =============================================================================
647 =============================================================================
654 Make sure the event gets sent to all clients
657 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
661 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
663 MSG_WriteByte (&sv.datagram, svc_particle);
664 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
665 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
666 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
667 for (i=0 ; i<3 ; i++)
668 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
669 MSG_WriteByte (&sv.datagram, count);
670 MSG_WriteByte (&sv.datagram, color);
671 SV_FlushBroadcastMessages();
678 Make sure the event gets sent to all clients
681 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
683 if (modelindex >= 256 || startframe >= 256)
685 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
687 MSG_WriteByte (&sv.datagram, svc_effect2);
688 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
689 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
690 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
691 MSG_WriteShort (&sv.datagram, modelindex);
692 MSG_WriteShort (&sv.datagram, startframe);
693 MSG_WriteByte (&sv.datagram, framecount);
694 MSG_WriteByte (&sv.datagram, framerate);
698 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
700 MSG_WriteByte (&sv.datagram, svc_effect);
701 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
702 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
703 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
704 MSG_WriteByte (&sv.datagram, modelindex);
705 MSG_WriteByte (&sv.datagram, startframe);
706 MSG_WriteByte (&sv.datagram, framecount);
707 MSG_WriteByte (&sv.datagram, framerate);
709 SV_FlushBroadcastMessages();
716 Each entity can have eight independant sound sources, like voice,
719 Channel 0 is an auto-allocate channel, the others override anything
720 already running on that entity/channel pair.
722 An attenuation of 0 will play full volume everywhere in the level.
723 Larger attenuations will drop off. (max 4 attenuation)
727 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int nvolume, float attenuation, qboolean reliable, float speed)
729 prvm_prog_t *prog = SVVM_prog;
731 int sound_num, field_mask, i, ent, speed4000;
733 dest = (reliable ? &sv.reliable_datagram : &sv.datagram);
735 if (nvolume < 0 || nvolume > 255)
737 Con_Printf ("SV_StartSound: volume = %i\n", nvolume);
741 if (attenuation < 0 || attenuation > 4)
743 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
747 if (!IS_CHAN(channel))
749 Con_Printf ("SV_StartSound: channel = %i\n", channel);
753 channel = CHAN_ENGINE2NET(channel);
755 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
758 // find precache number for sound
759 sound_num = SV_SoundIndex(sample, 1);
763 ent = PRVM_NUM_FOR_EDICT(entity);
765 speed4000 = (int)floor(speed * 4000.0f + 0.5f);
767 if (nvolume != DEFAULT_SOUND_PACKET_VOLUME)
768 field_mask |= SND_VOLUME;
769 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
770 field_mask |= SND_ATTENUATION;
771 if (speed4000 && speed4000 != 4000)
772 field_mask |= SND_SPEEDUSHORT4000;
773 if (ent >= 8192 || channel < 0 || channel > 7)
774 field_mask |= SND_LARGEENTITY;
775 if (sound_num >= 256)
776 field_mask |= SND_LARGESOUND;
778 // directed messages go only to the entity they are targeted on
779 MSG_WriteByte (dest, svc_sound);
780 MSG_WriteByte (dest, field_mask);
781 if (field_mask & SND_VOLUME)
782 MSG_WriteByte (dest, nvolume);
783 if (field_mask & SND_ATTENUATION)
784 MSG_WriteByte (dest, (int)(attenuation*64));
785 if (field_mask & SND_SPEEDUSHORT4000)
786 MSG_WriteShort (dest, speed4000);
787 if (field_mask & SND_LARGEENTITY)
789 MSG_WriteShort (dest, ent);
790 MSG_WriteChar (dest, channel);
793 MSG_WriteShort (dest, (ent<<3) | channel);
794 if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_NEHAHRABJP2)
795 MSG_WriteShort (dest, sound_num);
797 MSG_WriteByte (dest, sound_num);
798 for (i = 0;i < 3;i++)
799 MSG_WriteCoord (dest, PRVM_serveredictvector(entity, origin)[i]+0.5*(PRVM_serveredictvector(entity, mins)[i]+PRVM_serveredictvector(entity, maxs)[i]), sv.protocol);
801 // TODO do we have to do anything here when dest is &sv.reliable_datagram?
803 SV_FlushBroadcastMessages();
810 Nearly the same logic as SV_StartSound, except an origin
811 instead of an entity is provided and channel is omitted.
813 The entity sent to the client is 0 (world) and the channel
814 is 0 (CHAN_AUTO). SND_LARGEENTITY will never occur in this
815 function, therefore the check for it is omitted.
819 void SV_StartPointSound (vec3_t origin, const char *sample, int nvolume, float attenuation, float speed)
821 int sound_num, field_mask, i, speed4000;
823 if (nvolume < 0 || nvolume > 255)
825 Con_Printf ("SV_StartPointSound: volume = %i\n", nvolume);
829 if (attenuation < 0 || attenuation > 4)
831 Con_Printf ("SV_StartPointSound: attenuation = %f\n", attenuation);
835 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
838 // find precache number for sound
839 sound_num = SV_SoundIndex(sample, 1);
843 speed4000 = (int)(speed * 40.0f);
845 if (nvolume != DEFAULT_SOUND_PACKET_VOLUME)
846 field_mask |= SND_VOLUME;
847 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
848 field_mask |= SND_ATTENUATION;
849 if (sound_num >= 256)
850 field_mask |= SND_LARGESOUND;
851 if (speed4000 && speed4000 != 4000)
852 field_mask |= SND_SPEEDUSHORT4000;
854 // directed messages go only to the entity they are targeted on
855 MSG_WriteByte (&sv.datagram, svc_sound);
856 MSG_WriteByte (&sv.datagram, field_mask);
857 if (field_mask & SND_VOLUME)
858 MSG_WriteByte (&sv.datagram, nvolume);
859 if (field_mask & SND_ATTENUATION)
860 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
861 if (field_mask & SND_SPEEDUSHORT4000)
862 MSG_WriteShort (&sv.datagram, speed4000);
863 // Always write entnum 0 for the world entity
864 MSG_WriteShort (&sv.datagram, (0<<3) | 0);
865 if (field_mask & SND_LARGESOUND)
866 MSG_WriteShort (&sv.datagram, sound_num);
868 MSG_WriteByte (&sv.datagram, sound_num);
869 for (i = 0;i < 3;i++)
870 MSG_WriteCoord (&sv.datagram, origin[i], sv.protocol);
871 SV_FlushBroadcastMessages();
875 ==============================================================================
879 ==============================================================================
886 Sends the first message from the server to a connected client.
887 This will be sent on the initial connection and upon each server load.
890 void SV_SendServerinfo (client_t *client)
892 prvm_prog_t *prog = SVVM_prog;
897 // we know that this client has a netconnection and thus is not a bot
899 // edicts get reallocated on level changes, so we need to update it here
900 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
902 // clear cached stuff that depends on the level
903 client->weaponmodel[0] = 0;
904 client->weaponmodelindex = 0;
906 // LadyHavoc: clear entityframe tracking
907 client->latestframenum = 0;
909 // initialize the movetime, so a speedhack can't make use of the time before this client joined
910 client->cmd.time = sv.time;
912 if (client->entitydatabase)
913 EntityFrame_FreeDatabase(client->entitydatabase);
914 if (client->entitydatabase4)
915 EntityFrame4_FreeDatabase(client->entitydatabase4);
916 if (client->entitydatabase5)
917 EntityFrame5_FreeDatabase(client->entitydatabase5);
919 memset(client->stats, 0, sizeof(client->stats));
920 memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits));
922 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)
924 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
925 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
926 else if (sv.protocol == PROTOCOL_DARKPLACES4)
927 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
929 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
932 // reset csqc entity versions
933 for (i = 0;i < prog->max_edicts;i++)
935 client->csqcentityscope[i] = 0;
936 client->csqcentitysendflags[i] = 0xFFFFFF;
938 for (i = 0;i < NUM_CSQCENTITYDB_FRAMES;i++)
940 client->csqcentityframehistory[i].num = 0;
941 client->csqcentityframehistory[i].framenum = -1;
943 client->csqcnumedicts = 0;
944 client->csqcentityframehistory_next = 0;
946 SZ_Clear (&client->netconnection->message);
947 MSG_WriteByte (&client->netconnection->message, svc_print);
948 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)\n", gamename, buildstring, prog->filecrc);
949 MSG_WriteString (&client->netconnection->message,message);
951 SV_StopDemoRecording(client); // to split up demos into different files
952 if(sv_autodemo_perclient.integer)
954 char demofile[MAX_OSPATH];
955 char ipaddress[MAX_QPATH];
958 // start a new demo file
959 LHNETADDRESS_ToString(&(client->netconnection->peeraddress), ipaddress, sizeof(ipaddress), true);
960 for(j = 0; ipaddress[j]; ++j)
961 if(!isalnum(ipaddress[j]))
963 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);
965 SV_StartDemoRecording(client, demofile, -1);
968 //[515]: init csprogs according to version of svprogs, check the crc, etc.
969 if (sv.csqc_progname[0])
971 Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
972 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
973 MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "csqc_progname %s\n", sv.csqc_progname));
974 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
975 MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "csqc_progsize %i\n", sv.csqc_progsize));
976 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
977 MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "csqc_progcrc %i\n", sv.csqc_progcrc));
979 if(client->sv_demo_file != NULL)
982 static char buf[NET_MAXMESSAGE];
985 sb.data = (unsigned char *) buf;
986 sb.maxsize = sizeof(buf);
988 while(MakeDownloadPacket(sv.csqc_progname, svs.csqc_progdata, sv.csqc_progsize, sv.csqc_progcrc, k++, &sb, sv.protocol))
989 SV_WriteDemoMessage(client, &sb, false);
992 //[515]: init stufftext string (it is sent before svc_serverinfo)
993 if (PRVM_GetString(prog, PRVM_serverglobalstring(SV_InitCmd)))
995 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
996 MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "%s\n", PRVM_GetString(prog, PRVM_serverglobalstring(SV_InitCmd))));
1000 //if (sv_allowdownloads.integer)
1001 // always send the info that the server supports the protocol, even if downloads are forbidden
1002 // only because of that, the CSQC exception can work
1004 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
1005 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 2\n");
1008 // send at this time so it's guaranteed to get executed at the right time
1012 host_client = client;
1013 Curl_SendRequirements();
1017 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
1018 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
1019 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
1021 if (!coop.integer && deathmatch.integer)
1022 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
1024 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
1026 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog, PRVM_serveredictstring(prog->edicts, message)));
1028 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
1029 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
1030 MSG_WriteByte (&client->netconnection->message, 0);
1032 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
1033 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
1034 MSG_WriteByte (&client->netconnection->message, 0);
1037 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
1038 MSG_WriteByte (&client->netconnection->message, (int)PRVM_serveredictfloat(prog->edicts, sounds));
1039 MSG_WriteByte (&client->netconnection->message, (int)PRVM_serveredictfloat(prog->edicts, sounds));
1042 // store this in clientcamera, too
1043 client->clientcamera = PRVM_NUM_FOR_EDICT(client->edict);
1044 MSG_WriteByte (&client->netconnection->message, svc_setview);
1045 MSG_WriteShort (&client->netconnection->message, client->clientcamera);
1047 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
1048 MSG_WriteByte (&client->netconnection->message, 1);
1050 client->prespawned = false; // need prespawn, spawn, etc
1051 client->spawned = false; // need prespawn, spawn, etc
1052 client->begun = false; // need prespawn, spawn, etc
1053 client->sendsignon = 1; // send this message, and increment to 2, 2 will be set to 0 by the prespawn command
1055 // clear movement info until client enters the new level properly
1056 memset(&client->cmd, 0, sizeof(client->cmd));
1057 client->movesequence = 0;
1058 client->movement_highestsequence_seen = 0;
1059 memset(&client->movement_count, 0, sizeof(client->movement_count));
1060 #ifdef NUM_PING_TIMES
1061 for (i = 0;i < NUM_PING_TIMES;i++)
1062 client->ping_times[i] = 0;
1063 client->num_pings = 0;
1067 // allow the client some time to send his keepalives, even if map loading took ages
1068 client->netconnection->timeout = realtime + net_connecttimeout.value;
1075 Initializes a client_t for a new net connection. This will only be called
1076 once for a player each game, not once for each level change.
1079 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
1081 prvm_prog_t *prog = SVVM_prog;
1085 client = svs.clients + clientnum;
1087 // set up the client_t
1090 float backupparms[NUM_SPAWN_PARMS];
1091 memcpy(backupparms, client->spawn_parms, sizeof(backupparms));
1092 memset(client, 0, sizeof(*client));
1093 memcpy(client->spawn_parms, backupparms, sizeof(backupparms));
1096 memset(client, 0, sizeof(*client));
1097 client->active = true;
1098 client->netconnection = netconnection;
1100 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
1102 if(client->netconnection && client->netconnection->crypto.authenticated)
1104 Con_Printf("%s connection to %s has been established: client is %s@%s%.*s, I am %.*s@%s%.*s\n",
1105 client->netconnection->crypto.use_aes ? "Encrypted" : "Authenticated",
1106 client->netconnection->address,
1107 client->netconnection->crypto.client_idfp[0] ? client->netconnection->crypto.client_idfp : "-",
1108 (client->netconnection->crypto.client_issigned || !client->netconnection->crypto.client_keyfp[0]) ? "" : "~",
1109 crypto_keyfp_recommended_length, client->netconnection->crypto.client_keyfp[0] ? client->netconnection->crypto.client_keyfp : "-",
1110 crypto_keyfp_recommended_length, client->netconnection->crypto.server_idfp[0] ? client->netconnection->crypto.server_idfp : "-",
1111 (client->netconnection->crypto.server_issigned || !client->netconnection->crypto.server_keyfp[0]) ? "" : "~",
1112 crypto_keyfp_recommended_length, client->netconnection->crypto.server_keyfp[0] ? client->netconnection->crypto.server_keyfp : "-"
1116 strlcpy(client->name, "unconnected", sizeof(client->name));
1117 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
1118 client->prespawned = false;
1119 client->spawned = false;
1120 client->begun = false;
1121 client->edict = PRVM_EDICT_NUM(clientnum+1);
1122 if (client->netconnection)
1123 client->netconnection->message.allowoverflow = true; // we can catch it
1124 // prepare the unreliable message buffer
1125 client->unreliablemsg.data = client->unreliablemsg_data;
1126 client->unreliablemsg.maxsize = sizeof(client->unreliablemsg_data);
1127 // updated by receiving "rate" command from client, this is also the default if not using a DP client
1128 client->rate = 1000000000;
1129 client->connecttime = realtime;
1133 // call the progs to get default spawn parms for the new client
1134 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
1135 PRVM_serverglobalfloat(time) = sv.time;
1136 PRVM_serverglobaledict(self) = 0;
1137 prog->ExecuteProgram(prog, PRVM_serverfunction(SetNewParms), "QC function SetNewParms is missing");
1138 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
1139 client->spawn_parms[i] = (&PRVM_serverglobalfloat(parm1))[i];
1141 // set up the entity for this client (including .colormap, .team, etc)
1142 PRVM_ED_ClearEdict(prog, client->edict);
1145 // don't call SendServerinfo for a fresh botclient because its fields have
1146 // not been set up by the qc yet
1147 if (client->netconnection)
1148 SV_SendServerinfo (client);
1150 client->prespawned = client->spawned = client->begun = true;
1155 ===============================================================================
1159 ===============================================================================
1163 =============================================================================
1165 The PVS must include a small area around the client to allow head bobbing
1166 or other small motion on the client side. Otherwise, a bob might cause an
1167 entity that should be visible to not show up, especially when the bob
1168 crosses a waterline.
1170 =============================================================================
1173 static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int enumber)
1175 prvm_prog_t *prog = SVVM_prog;
1177 unsigned int sendflags;
1178 unsigned int version;
1179 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
1180 unsigned int customizeentityforclient;
1181 unsigned int sendentity;
1184 vec3_t cullmins, cullmaxs;
1187 // fast path for games that do not use legacy entity networking
1188 // note: still networks clients even if they are legacy
1189 sendentity = PRVM_serveredictfunction(ent, SendEntity);
1190 if (sv_onlycsqcnetworking.integer && !sendentity && enumber > svs.maxclients)
1193 // this 2 billion unit check is actually to detect NAN origins
1194 // (we really don't want to send those)
1195 if (!(VectorLength2(PRVM_serveredictvector(ent, origin)) < 2000000000.0*2000000000.0))
1198 // EF_NODRAW prevents sending for any reason except for your own
1199 // client, so we must keep all clients in this superset
1200 effects = (unsigned)PRVM_serveredictfloat(ent, effects);
1202 // we can omit invisible entities with no effects that are not clients
1203 // LadyHavoc: this could kill tags attached to an invisible entity, I
1204 // just hope we never have to support that case
1205 i = (int)PRVM_serveredictfloat(ent, modelindex);
1206 modelindex = (i >= 1 && i < MAX_MODELS && PRVM_serveredictstring(ent, model) && *PRVM_GetString(prog, PRVM_serveredictstring(ent, model)) && sv.models[i]) ? i : 0;
1209 i = (int)(PRVM_serveredictfloat(ent, glow_size) * 0.25f);
1210 glowsize = (unsigned char)bound(0, i, 255);
1211 if (PRVM_serveredictfloat(ent, glow_trail))
1212 flags |= RENDER_GLOWTRAIL;
1213 if (PRVM_serveredictedict(ent, viewmodelforclient))
1214 flags |= RENDER_VIEWMODEL;
1216 v = PRVM_serveredictvector(ent, color);
1218 light[0] = (unsigned short)bound(0, f, 65535);
1220 light[1] = (unsigned short)bound(0, f, 65535);
1222 light[2] = (unsigned short)bound(0, f, 65535);
1223 f = PRVM_serveredictfloat(ent, light_lev);
1224 light[3] = (unsigned short)bound(0, f, 65535);
1225 lightstyle = (unsigned char)PRVM_serveredictfloat(ent, style);
1226 lightpflags = (unsigned char)PRVM_serveredictfloat(ent, pflags);
1228 if (gamemode == GAME_TENEBRAE)
1230 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
1234 lightpflags |= PFLAGS_FULLDYNAMIC;
1236 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
1240 light[0] = (int)(0.2*256);
1241 light[1] = (int)(1.0*256);
1242 light[2] = (int)(0.2*256);
1244 lightpflags |= PFLAGS_FULLDYNAMIC;
1248 specialvisibilityradius = 0;
1249 if (lightpflags & PFLAGS_FULLDYNAMIC)
1250 specialvisibilityradius = max(specialvisibilityradius, light[3]);
1252 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
1253 if (flags & RENDER_GLOWTRAIL)
1254 specialvisibilityradius = max(specialvisibilityradius, 100);
1255 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
1257 if (effects & EF_BRIGHTFIELD)
1258 specialvisibilityradius = max(specialvisibilityradius, 80);
1259 if (effects & EF_MUZZLEFLASH)
1260 specialvisibilityradius = max(specialvisibilityradius, 100);
1261 if (effects & EF_BRIGHTLIGHT)
1262 specialvisibilityradius = max(specialvisibilityradius, 400);
1263 if (effects & EF_DIMLIGHT)
1264 specialvisibilityradius = max(specialvisibilityradius, 200);
1265 if (effects & EF_RED)
1266 specialvisibilityradius = max(specialvisibilityradius, 200);
1267 if (effects & EF_BLUE)
1268 specialvisibilityradius = max(specialvisibilityradius, 200);
1269 if (effects & EF_FLAME)
1270 specialvisibilityradius = max(specialvisibilityradius, 250);
1271 if (effects & EF_STARDUST)
1272 specialvisibilityradius = max(specialvisibilityradius, 100);
1275 // early culling checks
1276 // (final culling is done by SV_MarkWriteEntityStateToClient)
1277 customizeentityforclient = PRVM_serveredictfunction(ent, customizeentityforclient);
1278 if (!customizeentityforclient && enumber > svs.maxclients && (!modelindex && !specialvisibilityradius))
1282 cs->active = ACTIVE_NETWORK;
1283 cs->number = enumber;
1284 VectorCopy(PRVM_serveredictvector(ent, origin), cs->origin);
1285 VectorCopy(PRVM_serveredictvector(ent, angles), cs->angles);
1287 cs->effects = effects;
1288 cs->colormap = (unsigned)PRVM_serveredictfloat(ent, colormap);
1289 cs->modelindex = modelindex;
1290 cs->skin = (unsigned)PRVM_serveredictfloat(ent, skin);
1291 cs->frame = (unsigned)PRVM_serveredictfloat(ent, frame);
1292 cs->viewmodelforclient = PRVM_serveredictedict(ent, viewmodelforclient);
1293 cs->exteriormodelforclient = PRVM_serveredictedict(ent, exteriormodeltoclient);
1294 cs->nodrawtoclient = PRVM_serveredictedict(ent, nodrawtoclient);
1295 cs->drawonlytoclient = PRVM_serveredictedict(ent, drawonlytoclient);
1296 cs->customizeentityforclient = customizeentityforclient;
1297 cs->tagentity = PRVM_serveredictedict(ent, tag_entity);
1298 cs->tagindex = (unsigned char)PRVM_serveredictfloat(ent, tag_index);
1299 cs->glowsize = glowsize;
1300 cs->traileffectnum = PRVM_serveredictfloat(ent, traileffectnum);
1302 // don't need to init cs->colormod because the defaultstate did that for us
1303 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
1304 v = PRVM_serveredictvector(ent, colormod);
1305 if (VectorLength2(v))
1307 i = (int)(v[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
1308 i = (int)(v[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
1309 i = (int)(v[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
1312 // don't need to init cs->glowmod because the defaultstate did that for us
1313 //cs->glowmod[0] = cs->glowmod[1] = cs->glowmod[2] = 32;
1314 v = PRVM_serveredictvector(ent, glowmod);
1315 if (VectorLength2(v))
1317 i = (int)(v[0] * 32.0f);cs->glowmod[0] = bound(0, i, 255);
1318 i = (int)(v[1] * 32.0f);cs->glowmod[1] = bound(0, i, 255);
1319 i = (int)(v[2] * 32.0f);cs->glowmod[2] = bound(0, i, 255);
1322 cs->modelindex = modelindex;
1325 f = (PRVM_serveredictfloat(ent, alpha) * 255.0f);
1329 cs->alpha = (unsigned char)bound(0, i, 255);
1332 f = (PRVM_serveredictfloat(ent, renderamt));
1336 cs->alpha = (unsigned char)bound(0, i, 255);
1340 f = (PRVM_serveredictfloat(ent, scale) * 16.0f);
1344 cs->scale = (unsigned char)bound(0, i, 255);
1347 cs->glowcolor = 254;
1348 f = PRVM_serveredictfloat(ent, glow_color);
1350 cs->glowcolor = (int)f;
1352 if (PRVM_serveredictfloat(ent, fullbright))
1353 cs->effects |= EF_FULLBRIGHT;
1355 f = PRVM_serveredictfloat(ent, modelflags);
1357 cs->effects |= ((unsigned int)f & 0xff) << 24;
1359 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_STEP)
1360 cs->flags |= RENDER_STEP;
1361 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)
1362 cs->flags |= RENDER_LOWPRECISION;
1363 if (PRVM_serveredictfloat(ent, colormap) >= 1024)
1364 cs->flags |= RENDER_COLORMAPPED;
1365 if (cs->viewmodelforclient)
1366 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
1368 if (PRVM_serveredictfloat(ent, sendcomplexanimation))
1370 cs->flags |= RENDER_COMPLEXANIMATION;
1371 if (PRVM_serveredictfloat(ent, skeletonindex) >= 1)
1372 cs->skeletonobject = ent->priv.server->skeleton;
1373 cs->framegroupblend[0].frame = PRVM_serveredictfloat(ent, frame);
1374 cs->framegroupblend[1].frame = PRVM_serveredictfloat(ent, frame2);
1375 cs->framegroupblend[2].frame = PRVM_serveredictfloat(ent, frame3);
1376 cs->framegroupblend[3].frame = PRVM_serveredictfloat(ent, frame4);
1377 cs->framegroupblend[0].start = PRVM_serveredictfloat(ent, frame1time);
1378 cs->framegroupblend[1].start = PRVM_serveredictfloat(ent, frame2time);
1379 cs->framegroupblend[2].start = PRVM_serveredictfloat(ent, frame3time);
1380 cs->framegroupblend[3].start = PRVM_serveredictfloat(ent, frame4time);
1381 cs->framegroupblend[1].lerp = PRVM_serveredictfloat(ent, lerpfrac);
1382 cs->framegroupblend[2].lerp = PRVM_serveredictfloat(ent, lerpfrac3);
1383 cs->framegroupblend[3].lerp = PRVM_serveredictfloat(ent, lerpfrac4);
1384 cs->framegroupblend[0].lerp = 1.0f - cs->framegroupblend[1].lerp - cs->framegroupblend[2].lerp - cs->framegroupblend[3].lerp;
1385 cs->frame = 0; // don't need the legacy frame
1388 cs->light[0] = light[0];
1389 cs->light[1] = light[1];
1390 cs->light[2] = light[2];
1391 cs->light[3] = light[3];
1392 cs->lightstyle = lightstyle;
1393 cs->lightpflags = lightpflags;
1395 cs->specialvisibilityradius = specialvisibilityradius;
1397 // calculate the visible box of this entity (don't use the physics box
1398 // as that is often smaller than a model, and would not count
1399 // specialvisibilityradius)
1400 if ((model = SV_GetModelByIndex(modelindex)) && (model->type != mod_null))
1402 float scale = cs->scale * (1.0f / 16.0f);
1403 if (cs->angles[0] || cs->angles[2]) // pitch and roll
1405 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
1406 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
1408 else if (cs->angles[1] || ((effects | model->effects) & EF_ROTATE))
1410 VectorMA(cs->origin, scale, model->yawmins, cullmins);
1411 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
1415 VectorMA(cs->origin, scale, model->normalmins, cullmins);
1416 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
1421 // if there is no model (or it could not be loaded), use the physics box
1422 VectorAdd(cs->origin, PRVM_serveredictvector(ent, mins), cullmins);
1423 VectorAdd(cs->origin, PRVM_serveredictvector(ent, maxs), cullmaxs);
1425 if (specialvisibilityradius)
1427 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
1428 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
1429 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
1430 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
1431 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
1432 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
1435 // calculate center of bbox for network prioritization purposes
1436 VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
1438 // if culling box has moved, update pvs cluster links
1439 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
1441 VectorCopy(cullmins, ent->priv.server->cullmins);
1442 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
1443 // a value of -1 for pvs_numclusters indicates that the links are not
1444 // cached, and should be re-tested each time, this is the case if the
1445 // culling box touches too many pvs clusters to store, or if the world
1446 // model does not support FindBoxClusters
1447 ent->priv.server->pvs_numclusters = -1;
1448 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
1450 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
1451 if (i <= MAX_ENTITYCLUSTERS)
1452 ent->priv.server->pvs_numclusters = i;
1456 // we need to do some csqc entity upkeep here
1457 // get self.SendFlags and clear them
1458 // (to let the QC know that they've been read)
1461 sendflags = (unsigned int)PRVM_serveredictfloat(ent, SendFlags);
1462 PRVM_serveredictfloat(ent, SendFlags) = 0;
1463 // legacy self.Version system
1464 if ((version = (unsigned int)PRVM_serveredictfloat(ent, Version)))
1466 if (sv.csqcentityversion[enumber] != version)
1467 sendflags = 0xFFFFFF;
1468 sv.csqcentityversion[enumber] = version;
1470 // move sendflags into the per-client sendflags
1472 for (i = 0;i < svs.maxclients;i++)
1473 svs.clients[i].csqcentitysendflags[enumber] |= sendflags;
1474 // mark it as inactive for non-csqc networking
1475 cs->active = ACTIVE_SHARED;
1481 static void SV_PrepareEntitiesForSending(void)
1483 prvm_prog_t *prog = SVVM_prog;
1486 // send all entities that touch the pvs
1487 sv.numsendentities = 0;
1488 sv.sendentitiesindex[0] = NULL;
1489 memset(sv.sendentitiesindex, 0, prog->num_edicts * sizeof(*sv.sendentitiesindex));
1490 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
1492 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sv.sendentities + sv.numsendentities, e))
1494 sv.sendentitiesindex[e] = sv.sendentities + sv.numsendentities;
1495 sv.numsendentities++;
1500 #define MAX_LINEOFSIGHTTRACES 64
1502 qboolean SV_CanSeeBox(int numtraces, vec_t eyejitter, vec_t enlarge, vec_t entboxexpand, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
1504 prvm_prog_t *prog = SVVM_prog;
1507 float starttransformed[3], endtransformed[3];
1508 float boxminstransformed[3], boxmaxstransformed[3];
1509 float localboxcenter[3], localboxextents[3], localboxmins[3], localboxmaxs[3];
1512 int originalnumtouchedicts;
1513 int numtouchedicts = 0;
1515 matrix4x4_t matrix, imatrix;
1517 prvm_edict_t *touch;
1518 static prvm_edict_t *touchedicts[MAX_EDICTS];
1519 vec3_t eyemins, eyemaxs, start;
1520 vec3_t boxmins, boxmaxs;
1521 vec3_t clipboxmins, clipboxmaxs;
1522 vec3_t endpoints[MAX_LINEOFSIGHTTRACES];
1524 numtraces = min(numtraces, MAX_LINEOFSIGHTTRACES);
1526 // jitter the eye location within this box
1527 eyemins[0] = eye[0] - eyejitter;
1528 eyemaxs[0] = eye[0] + eyejitter;
1529 eyemins[1] = eye[1] - eyejitter;
1530 eyemaxs[1] = eye[1] + eyejitter;
1531 eyemins[2] = eye[2] - eyejitter;
1532 eyemaxs[2] = eye[2] + eyejitter;
1533 // expand the box a little
1534 boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0] - entboxexpand;
1535 boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0] + entboxexpand;
1536 boxmins[1] = (enlarge+1) * entboxmins[1] - enlarge * entboxmaxs[1] - entboxexpand;
1537 boxmaxs[1] = (enlarge+1) * entboxmaxs[1] - enlarge * entboxmins[1] + entboxexpand;
1538 boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2] - entboxexpand;
1539 boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2] + entboxexpand;
1541 VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, endpoints[0]);
1542 for (traceindex = 1;traceindex < numtraces;traceindex++)
1543 VectorSet(endpoints[traceindex], lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
1545 // calculate sweep box for the entire swarm of traces
1546 VectorCopy(eyemins, clipboxmins);
1547 VectorCopy(eyemaxs, clipboxmaxs);
1548 for (traceindex = 0;traceindex < numtraces;traceindex++)
1550 clipboxmins[0] = min(clipboxmins[0], endpoints[traceindex][0]);
1551 clipboxmins[1] = min(clipboxmins[1], endpoints[traceindex][1]);
1552 clipboxmins[2] = min(clipboxmins[2], endpoints[traceindex][2]);
1553 clipboxmaxs[0] = max(clipboxmaxs[0], endpoints[traceindex][0]);
1554 clipboxmaxs[1] = max(clipboxmaxs[1], endpoints[traceindex][1]);
1555 clipboxmaxs[2] = max(clipboxmaxs[2], endpoints[traceindex][2]);
1558 // get the list of entities in the sweep box
1559 if (sv_cullentities_trace_entityocclusion.integer)
1560 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
1561 if (numtouchedicts > MAX_EDICTS)
1563 // this never happens
1564 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1565 numtouchedicts = MAX_EDICTS;
1567 // iterate the entities found in the sweep box and filter them
1568 originalnumtouchedicts = numtouchedicts;
1570 for (touchindex = 0;touchindex < originalnumtouchedicts;touchindex++)
1572 touch = touchedicts[touchindex];
1573 if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
1575 model = SV_GetModelFromEdict(touch);
1576 if (!model || !model->brush.TraceLineOfSight)
1578 // skip obviously transparent entities
1579 alpha = PRVM_serveredictfloat(touch, alpha);
1580 if (alpha && alpha < 1)
1582 if ((int)PRVM_serveredictfloat(touch, effects) & EF_ADDITIVE)
1584 touchedicts[numtouchedicts++] = touch;
1587 // now that we have a filtered list of "interesting" entities, fire each
1588 // ray against all of them, this gives us an early-out case when something
1589 // is visible (which it often is)
1591 for (traceindex = 0;traceindex < numtraces;traceindex++)
1593 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
1594 // check world occlusion
1595 if (sv.worldmodel && sv.worldmodel->brush.TraceLineOfSight)
1596 if (!sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, start, endpoints[traceindex], boxmins, boxmaxs))
1598 for (touchindex = 0;touchindex < numtouchedicts;touchindex++)
1600 touch = touchedicts[touchindex];
1601 model = SV_GetModelFromEdict(touch);
1602 if(model && model->brush.TraceLineOfSight)
1604 // get the entity matrix
1605 pitchsign = SV_GetPitchSign(prog, touch);
1606 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);
1607 Matrix4x4_Invert_Simple(&imatrix, &matrix);
1608 // see if the ray hits this entity
1609 Matrix4x4_Transform(&imatrix, start, starttransformed);
1610 Matrix4x4_Transform(&imatrix, endpoints[traceindex], endtransformed);
1611 Matrix4x4_Transform(&imatrix, boxmins, boxminstransformed);
1612 Matrix4x4_Transform(&imatrix, boxmaxs, boxmaxstransformed);
1613 // transform the AABB to local space
1614 VectorMAM(0.5f, boxminstransformed, 0.5f, boxmaxstransformed, localboxcenter);
1615 localboxextents[0] = fabs(boxmaxstransformed[0] - localboxcenter[0]);
1616 localboxextents[1] = fabs(boxmaxstransformed[1] - localboxcenter[1]);
1617 localboxextents[2] = fabs(boxmaxstransformed[2] - localboxcenter[2]);
1618 localboxmins[0] = localboxcenter[0] - localboxextents[0];
1619 localboxmins[1] = localboxcenter[1] - localboxextents[1];
1620 localboxmins[2] = localboxcenter[2] - localboxextents[2];
1621 localboxmaxs[0] = localboxcenter[0] + localboxextents[0];
1622 localboxmaxs[1] = localboxcenter[1] + localboxextents[1];
1623 localboxmaxs[2] = localboxcenter[2] + localboxextents[2];
1624 if (!model->brush.TraceLineOfSight(model, starttransformed, endtransformed, localboxmins, localboxmaxs))
1631 // check if the ray was blocked
1632 if (touchindex < numtouchedicts)
1634 // return if the ray was not blocked
1642 static void SV_MarkWriteEntityStateToClient(entity_state_t *s)
1644 prvm_prog_t *prog = SVVM_prog;
1648 if (sv.sententitiesconsideration[s->number] == sv.sententitiesmark)
1650 sv.sententitiesconsideration[s->number] = sv.sententitiesmark;
1651 sv.writeentitiestoclient_stats_totalentities++;
1653 if (s->customizeentityforclient)
1655 PRVM_serverglobalfloat(time) = sv.time;
1656 PRVM_serverglobaledict(self) = s->number;
1657 PRVM_serverglobaledict(other) = sv.writeentitiestoclient_cliententitynumber;
1658 prog->ExecuteProgram(prog, s->customizeentityforclient, "customizeentityforclient: NULL function");
1659 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
1663 // never reject player
1664 if (s->number != sv.writeentitiestoclient_cliententitynumber)
1666 // check various rejection conditions
1667 if (s->nodrawtoclient == sv.writeentitiestoclient_cliententitynumber)
1669 if (s->drawonlytoclient && s->drawonlytoclient != sv.writeentitiestoclient_cliententitynumber)
1671 if (s->effects & EF_NODRAW)
1673 // LadyHavoc: only send entities with a model or important effects
1674 if (!s->modelindex && s->specialvisibilityradius == 0)
1677 isbmodel = (model = SV_GetModelByIndex(s->modelindex)) != NULL && model->name[0] == '*';
1678 // viewmodels don't have visibility checking
1679 if (s->viewmodelforclient)
1681 if (s->viewmodelforclient != sv.writeentitiestoclient_cliententitynumber)
1684 else if (s->tagentity)
1686 // tag attached entities simply check their parent
1687 if (!sv.sendentitiesindex[s->tagentity])
1689 SV_MarkWriteEntityStateToClient(sv.sendentitiesindex[s->tagentity]);
1690 if (sv.sententities[s->tagentity] != sv.sententitiesmark)
1693 // always send world submodels in newer protocols because they don't
1694 // generate much traffic (in old protocols they hog bandwidth)
1695 // but only if sv_cullentities_nevercullbmodels is off
1696 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
1698 // entity has survived every check so far, check if visible
1699 ed = PRVM_EDICT_NUM(s->number);
1701 // if not touching a visible leaf
1702 if (sv_cullentities_pvs.integer && !r_novis.integer && !r_trippy.integer && sv.writeentitiestoclient_pvsbytes)
1704 if (ed->priv.server->pvs_numclusters < 0)
1706 // entity too big for clusters list
1707 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv.writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
1709 sv.writeentitiestoclient_stats_culled_pvs++;
1716 // check cached clusters list
1717 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
1718 if (CHECKPVSBIT(sv.writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
1720 if (i == ed->priv.server->pvs_numclusters)
1722 sv.writeentitiestoclient_stats_culled_pvs++;
1728 // or not seen by random tracelines
1729 if (sv_cullentities_trace.integer && !isbmodel && sv.worldmodel && sv.worldmodel->brush.TraceLineOfSight && !r_trippy.integer)
1732 s->number <= svs.maxclients
1733 ? sv_cullentities_trace_samples_players.integer
1735 s->specialvisibilityradius
1736 ? sv_cullentities_trace_samples_extra.integer
1737 : sv_cullentities_trace_samples.integer;
1738 float enlarge = sv_cullentities_trace_enlarge.value;
1743 for (eyeindex = 0;eyeindex < sv.writeentitiestoclient_numeyes;eyeindex++)
1744 if(SV_CanSeeBox(samples, sv_cullentities_trace_eyejitter.value, enlarge, sv_cullentities_trace_expand.value, sv.writeentitiestoclient_eyes[eyeindex], ed->priv.server->cullmins, ed->priv.server->cullmaxs))
1746 if(eyeindex < sv.writeentitiestoclient_numeyes)
1747 svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number] =
1749 s->number <= svs.maxclients
1750 ? sv_cullentities_trace_delay_players.value
1751 : sv_cullentities_trace_delay.value
1753 else if (realtime > svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number])
1755 sv.writeentitiestoclient_stats_culled_trace++;
1763 // this just marks it for sending
1764 // FIXME: it would be more efficient to send here, but the entity
1765 // compressor isn't that flexible
1766 sv.writeentitiestoclient_stats_visibleentities++;
1767 sv.sententities[s->number] = sv.sententitiesmark;
1770 #if MAX_LEVELNETWORKEYES > 0
1771 #define MAX_EYE_RECURSION 1 // increase if recursion gets supported by portals
1772 static void SV_AddCameraEyes(void)
1774 prvm_prog_t *prog = SVVM_prog;
1777 static int cameras[MAX_LEVELNETWORKEYES];
1778 static vec3_t camera_origins[MAX_LEVELNETWORKEYES];
1779 static int eye_levels[MAX_CLIENTNETWORKEYES];
1783 for(i = 0; i < sv.writeentitiestoclient_numeyes; ++i)
1786 // check line of sight to portal entities and add them to PVS
1787 for (e = 1, ed = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ed = PRVM_NEXT_EDICT(ed))
1789 if (!ed->priv.server->free)
1791 if(PRVM_serveredictfunction(ed, camera_transform))
1793 PRVM_serverglobalfloat(time) = sv.time;
1794 PRVM_serverglobaledict(self) = e;
1795 PRVM_serverglobaledict(other) = sv.writeentitiestoclient_cliententitynumber;
1796 VectorCopy(sv.writeentitiestoclient_eyes[0], PRVM_serverglobalvector(trace_endpos));
1797 VectorCopy(sv.writeentitiestoclient_eyes[0], PRVM_G_VECTOR(OFS_PARM0));
1798 VectorClear(PRVM_G_VECTOR(OFS_PARM1));
1799 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ed, camera_transform), "QC function e.camera_transform is missing");
1800 if(!VectorCompare(PRVM_serverglobalvector(trace_endpos), sv.writeentitiestoclient_eyes[0]))
1802 VectorCopy(PRVM_serverglobalvector(trace_endpos), camera_origins[n_cameras]);
1803 cameras[n_cameras] = e;
1805 if(n_cameras >= MAX_LEVELNETWORKEYES)
1815 // i is loop counter, is reset to 0 when an eye got added
1816 // j is camera index to check
1817 for(i = 0, j = 0; sv.writeentitiestoclient_numeyes < MAX_CLIENTNETWORKEYES && i < n_cameras; ++i, ++j, j %= n_cameras)
1821 ed = PRVM_EDICT_NUM(cameras[j]);
1822 VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, mins), mi);
1823 VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, maxs), ma);
1824 for(k = 0; k < sv.writeentitiestoclient_numeyes; ++k)
1825 if(eye_levels[k] <= MAX_EYE_RECURSION)
1827 if(SV_CanSeeBox(sv_cullentities_trace_samples.integer, sv_cullentities_trace_eyejitter.value, sv_cullentities_trace_enlarge.value, sv_cullentities_trace_expand.value, sv.writeentitiestoclient_eyes[k], mi, ma))
1829 eye_levels[sv.writeentitiestoclient_numeyes] = eye_levels[k] + 1;
1830 VectorCopy(camera_origins[j], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
1831 // 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);
1832 sv.writeentitiestoclient_numeyes++;
1841 void SV_AddCameraEyes(void)
1846 static void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int maxsize)
1848 prvm_prog_t *prog = SVVM_prog;
1849 qboolean need_empty = false;
1850 int i, numsendstates, numcsqcsendstates;
1852 prvm_edict_t *camera;
1856 // if there isn't enough space to accomplish anything, skip it
1857 if (msg->cursize + 25 > maxsize)
1860 sv.writeentitiestoclient_msg = msg;
1861 sv.writeentitiestoclient_clientnumber = client - svs.clients;
1863 sv.writeentitiestoclient_stats_culled_pvs = 0;
1864 sv.writeentitiestoclient_stats_culled_trace = 0;
1865 sv.writeentitiestoclient_stats_visibleentities = 0;
1866 sv.writeentitiestoclient_stats_totalentities = 0;
1867 sv.writeentitiestoclient_numeyes = 0;
1870 sv.writeentitiestoclient_cliententitynumber = PRVM_EDICT_TO_PROG(clent); // LadyHavoc: for comparison purposes
1871 camera = PRVM_EDICT_NUM( client->clientcamera );
1872 VectorAdd(PRVM_serveredictvector(camera, origin), PRVM_serveredictvector(clent, view_ofs), eye);
1873 sv.writeentitiestoclient_pvsbytes = 0;
1874 // get the PVS values for the eye location, later FatPVS calls will merge
1875 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
1876 sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, eye, 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs), sv.writeentitiestoclient_pvsbytes != 0);
1878 // add the eye to a list for SV_CanSeeBox tests
1879 VectorCopy(eye, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
1880 sv.writeentitiestoclient_numeyes++;
1882 // calculate predicted eye origin for SV_CanSeeBox tests
1883 if (sv_cullentities_trace_prediction.integer)
1885 vec_t predtime = bound(0, host_client->ping, sv_cullentities_trace_prediction_time.value);
1887 VectorMA(eye, predtime, PRVM_serveredictvector(camera, velocity), predeye);
1888 if (SV_CanSeeBox(1, 0, 0, 0, eye, predeye, predeye))
1890 VectorCopy(predeye, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
1891 sv.writeentitiestoclient_numeyes++;
1893 //if (!sv.writeentitiestoclient_useprediction)
1894 // Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
1899 // build PVS from the new eyes
1900 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
1901 for(i = 1; i < sv.writeentitiestoclient_numeyes; ++i)
1902 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);
1904 sv.sententitiesmark++;
1906 for (i = 0;i < sv.numsendentities;i++)
1907 SV_MarkWriteEntityStateToClient(sv.sendentities + i);
1910 numcsqcsendstates = 0;
1911 for (i = 0;i < sv.numsendentities;i++)
1913 s = &sv.sendentities[i];
1914 if (sv.sententities[s->number] == sv.sententitiesmark)
1916 if(s->active == ACTIVE_NETWORK)
1918 if (s->exteriormodelforclient)
1920 if (s->exteriormodelforclient == sv.writeentitiestoclient_cliententitynumber)
1921 s->flags |= RENDER_EXTERIORMODEL;
1923 s->flags &= ~RENDER_EXTERIORMODEL;
1925 sv.writeentitiestoclient_sendstates[numsendstates++] = s;
1927 else if(sv.sendentities[i].active == ACTIVE_SHARED)
1928 sv.writeentitiestoclient_csqcsendstates[numcsqcsendstates++] = s->number;
1930 Con_Printf("entity %d is in sv.sendentities and marked, but not active, please breakpoint me\n", s->number);
1934 if (sv_cullentities_stats.integer)
1935 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);
1937 if(client->entitydatabase5)
1938 need_empty = EntityFrameCSQC_WriteFrame(msg, maxsize, numcsqcsendstates, sv.writeentitiestoclient_csqcsendstates, client->entitydatabase5->latestframenum + 1);
1940 EntityFrameCSQC_WriteFrame(msg, maxsize, numcsqcsendstates, sv.writeentitiestoclient_csqcsendstates, 0);
1942 // force every 16th frame to be not empty (or cl_movement replay takes
1944 // BTW, this should normally not kick in any more due to the check
1945 // below, except if the client stopped sending movement frames
1946 if(client->num_skippedentityframes >= 16)
1949 // help cl_movement a bit more
1950 if(client->movesequence != client->lastmovesequence)
1952 client->lastmovesequence = client->movesequence;
1954 if (client->entitydatabase5)
1955 success = EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence, need_empty);
1956 else if (client->entitydatabase4)
1958 success = EntityFrame4_WriteFrame(msg, maxsize, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates);
1959 Protocol_WriteStatsReliable();
1961 else if (client->entitydatabase)
1963 success = EntityFrame_WriteFrame(msg, maxsize, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1);
1964 Protocol_WriteStatsReliable();
1968 success = EntityFrameQuake_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates);
1969 Protocol_WriteStatsReliable();
1973 client->num_skippedentityframes = 0;
1975 ++client->num_skippedentityframes;
1984 static void SV_CleanupEnts (void)
1986 prvm_prog_t *prog = SVVM_prog;
1990 ent = PRVM_NEXT_EDICT(prog->edicts);
1991 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1992 PRVM_serveredictfloat(ent, effects) = (int)PRVM_serveredictfloat(ent, effects) & ~EF_MUZZLEFLASH;
1997 SV_WriteClientdataToMessage
2001 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
2003 prvm_prog_t *prog = SVVM_prog;
2006 prvm_edict_t *other;
2011 float *statsf = (float *)stats;
2015 // send a damage message
2017 if (PRVM_serveredictfloat(ent, dmg_take) || PRVM_serveredictfloat(ent, dmg_save))
2019 other = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, dmg_inflictor));
2020 MSG_WriteByte (msg, svc_damage);
2021 MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_save));
2022 MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_take));
2023 for (i=0 ; i<3 ; i++)
2024 MSG_WriteCoord (msg, PRVM_serveredictvector(other, origin)[i] + 0.5*(PRVM_serveredictvector(other, mins)[i] + PRVM_serveredictvector(other, maxs)[i]), sv.protocol);
2026 PRVM_serveredictfloat(ent, dmg_take) = 0;
2027 PRVM_serveredictfloat(ent, dmg_save) = 0;
2031 // send the current viewpos offset from the view entity
2033 SV_SetIdealPitch (); // how much to look up / down ideally
2035 // a fixangle might get lost in a dropped packet. Oh well.
2036 if(PRVM_serveredictfloat(ent, fixangle))
2038 // angle fixing was requested by global thinking code...
2039 // so store the current angles for later use
2040 VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles);
2041 host_client->fixangle_angles_set = true;
2043 // and clear fixangle for the next frame
2044 PRVM_serveredictfloat(ent, fixangle) = 0;
2047 if (host_client->fixangle_angles_set)
2049 MSG_WriteByte (msg, svc_setangle);
2050 for (i=0 ; i < 3 ; i++)
2051 MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
2052 host_client->fixangle_angles_set = false;
2055 // the runes are in serverflags, pack them into the items value, also pack
2056 // in the items2 value for mission pack huds
2057 // (used only in the mission packs, which do not use serverflags)
2058 items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serveredictfloat(ent, items2) << 23) | ((int)PRVM_serverglobalfloat(serverflags) << 28);
2060 VectorCopy(PRVM_serveredictvector(ent, punchvector), punchvector);
2062 // cache weapon model name and index in client struct to save time
2063 // (this search can be almost 1% of cpu time!)
2064 s = PRVM_GetString(prog, PRVM_serveredictstring(ent, weaponmodel));
2065 if (strcmp(s, client->weaponmodel))
2067 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
2068 client->weaponmodelindex = SV_ModelIndex(s, 1);
2071 viewzoom = (int)(PRVM_serveredictfloat(ent, viewzoom) * 255.0f);
2077 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2078 bits |= SU_ONGROUND;
2079 if (PRVM_serveredictfloat(ent, waterlevel) >= 2)
2081 if (PRVM_serveredictfloat(ent, idealpitch))
2082 bits |= SU_IDEALPITCH;
2084 for (i=0 ; i<3 ; i++)
2086 if (PRVM_serveredictvector(ent, punchangle)[i])
2087 bits |= (SU_PUNCH1<<i);
2088 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)
2090 bits |= (SU_PUNCHVEC1<<i);
2091 if (PRVM_serveredictvector(ent, velocity)[i])
2092 bits |= (SU_VELOCITY1<<i);
2095 gravity = PRVM_serveredictfloat(ent, gravity);if (!gravity) gravity = 1.0f;
2097 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
2098 stats[STAT_VIEWHEIGHT] = (int)PRVM_serveredictvector(ent, view_ofs)[2];
2099 stats[STAT_ITEMS] = items;
2100 stats[STAT_WEAPONFRAME] = (int)PRVM_serveredictfloat(ent, weaponframe);
2101 stats[STAT_ARMOR] = (int)PRVM_serveredictfloat(ent, armorvalue);
2102 stats[STAT_WEAPON] = client->weaponmodelindex;
2103 stats[STAT_HEALTH] = (int)PRVM_serveredictfloat(ent, health);
2104 stats[STAT_AMMO] = (int)PRVM_serveredictfloat(ent, currentammo);
2105 stats[STAT_SHELLS] = (int)PRVM_serveredictfloat(ent, ammo_shells);
2106 stats[STAT_NAILS] = (int)PRVM_serveredictfloat(ent, ammo_nails);
2107 stats[STAT_ROCKETS] = (int)PRVM_serveredictfloat(ent, ammo_rockets);
2108 stats[STAT_CELLS] = (int)PRVM_serveredictfloat(ent, ammo_cells);
2109 stats[STAT_ACTIVEWEAPON] = (int)PRVM_serveredictfloat(ent, weapon);
2110 stats[STAT_VIEWZOOM] = viewzoom;
2111 stats[STAT_TOTALSECRETS] = (int)PRVM_serverglobalfloat(total_secrets);
2112 stats[STAT_TOTALMONSTERS] = (int)PRVM_serverglobalfloat(total_monsters);
2113 // the QC bumps these itself by sending svc_'s, so we have to keep them
2114 // zero or they'll be corrected by the engine
2115 //stats[STAT_SECRETS] = PRVM_serverglobalfloat(found_secrets);
2116 //stats[STAT_MONSTERS] = PRVM_serverglobalfloat(killed_monsters);
2118 // movement settings for prediction
2119 // note: these are not sent in protocols with lower MAX_CL_STATS limits
2120 stats[STAT_MOVEFLAGS] = MOVEFLAG_VALID
2121 | (sv_gameplayfix_q2airaccelerate.integer ? MOVEFLAG_Q2AIRACCELERATE : 0)
2122 | (sv_gameplayfix_nogravityonground.integer ? MOVEFLAG_NOGRAVITYONGROUND : 0)
2123 | (sv_gameplayfix_gravityunaffectedbyticrate.integer ? MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE : 0)
2125 statsf[STAT_MOVEVARS_TICRATE] = sys_ticrate.value;
2126 statsf[STAT_MOVEVARS_TIMESCALE] = host_timescale.value;
2127 statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
2128 statsf[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
2129 statsf[STAT_MOVEVARS_MAXSPEED] = sv_maxspeed.value;
2130 statsf[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_maxspeed.value; // FIXME: QW has a separate cvar for this
2131 statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
2132 statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value >= 0 ? sv_airaccelerate.value : sv_accelerate.value;
2133 statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value >= 0 ? sv_wateraccelerate.value : sv_accelerate.value;
2134 statsf[STAT_MOVEVARS_ENTGRAVITY] = gravity;
2135 statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value;
2136 statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
2137 statsf[STAT_MOVEVARS_MAXAIRSPEED] = sv_maxairspeed.value;
2138 statsf[STAT_MOVEVARS_STEPHEIGHT] = sv_stepheight.value;
2139 statsf[STAT_MOVEVARS_AIRACCEL_QW] = sv_airaccel_qw.value;
2140 statsf[STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR] = sv_airaccel_qw_stretchfactor.value;
2141 statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value;
2142 statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value;
2143 statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value >= 0 ? sv_waterfriction.value : sv_friction.value;
2144 statsf[STAT_MOVEVARS_AIRSTOPACCELERATE] = sv_airstopaccelerate.value;
2145 statsf[STAT_MOVEVARS_AIRSTRAFEACCELERATE] = sv_airstrafeaccelerate.value;
2146 statsf[STAT_MOVEVARS_MAXAIRSTRAFESPEED] = sv_maxairstrafespeed.value;
2147 statsf[STAT_MOVEVARS_AIRSTRAFEACCEL_QW] = sv_airstrafeaccel_qw.value;
2148 statsf[STAT_MOVEVARS_AIRCONTROL] = sv_aircontrol.value;
2149 statsf[STAT_MOVEVARS_AIRCONTROL_POWER] = sv_aircontrol_power.value;
2150 statsf[STAT_MOVEVARS_AIRCONTROL_PENALTY] = sv_aircontrol_penalty.value;
2151 statsf[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL] = sv_warsowbunny_airforwardaccel.value;
2152 statsf[STAT_MOVEVARS_WARSOWBUNNY_ACCEL] = sv_warsowbunny_accel.value;
2153 statsf[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED] = sv_warsowbunny_topspeed.value;
2154 statsf[STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL] = sv_warsowbunny_turnaccel.value;
2155 statsf[STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO] = sv_warsowbunny_backtosideratio.value;
2156 statsf[STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW] = sv_airspeedlimit_nonqw.value;
2157 statsf[STAT_FRAGLIMIT] = fraglimit.value;
2158 statsf[STAT_TIMELIMIT] = timelimit.value;
2160 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)
2162 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
2164 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
2165 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
2167 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
2168 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
2169 if (viewzoom != 255)
2170 bits |= SU_VIEWZOOM;
2175 if (bits >= 16777216)
2179 MSG_WriteByte (msg, svc_clientdata);
2180 MSG_WriteShort (msg, bits);
2181 if (bits & SU_EXTEND1)
2182 MSG_WriteByte(msg, bits >> 16);
2183 if (bits & SU_EXTEND2)
2184 MSG_WriteByte(msg, bits >> 24);
2186 if (bits & SU_VIEWHEIGHT)
2187 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
2189 if (bits & SU_IDEALPITCH)
2190 MSG_WriteChar (msg, (int)PRVM_serveredictfloat(ent, idealpitch));
2192 for (i=0 ; i<3 ; i++)
2194 if (bits & (SU_PUNCH1<<i))
2196 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)
2197 MSG_WriteChar(msg, (int)PRVM_serveredictvector(ent, punchangle)[i]);
2199 MSG_WriteAngle16i(msg, PRVM_serveredictvector(ent, punchangle)[i]);
2201 if (bits & (SU_PUNCHVEC1<<i))
2203 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
2204 MSG_WriteCoord16i(msg, punchvector[i]);
2206 MSG_WriteCoord32f(msg, punchvector[i]);
2208 if (bits & (SU_VELOCITY1<<i))
2210 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)
2211 MSG_WriteChar(msg, (int)(PRVM_serveredictvector(ent, velocity)[i] * (1.0f / 16.0f)));
2213 MSG_WriteCoord32f(msg, PRVM_serveredictvector(ent, velocity)[i]);
2217 if (bits & SU_ITEMS)
2218 MSG_WriteLong (msg, stats[STAT_ITEMS]);
2220 if (sv.protocol == PROTOCOL_DARKPLACES5)
2222 if (bits & SU_WEAPONFRAME)
2223 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
2224 if (bits & SU_ARMOR)
2225 MSG_WriteShort (msg, stats[STAT_ARMOR]);
2226 if (bits & SU_WEAPON)
2227 MSG_WriteShort (msg, stats[STAT_WEAPON]);
2228 MSG_WriteShort (msg, stats[STAT_HEALTH]);
2229 MSG_WriteShort (msg, stats[STAT_AMMO]);
2230 MSG_WriteShort (msg, stats[STAT_SHELLS]);
2231 MSG_WriteShort (msg, stats[STAT_NAILS]);
2232 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
2233 MSG_WriteShort (msg, stats[STAT_CELLS]);
2234 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
2235 if (bits & SU_VIEWZOOM)
2236 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
2238 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)
2240 if (bits & SU_WEAPONFRAME)
2241 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
2242 if (bits & SU_ARMOR)
2243 MSG_WriteByte (msg, stats[STAT_ARMOR]);
2244 if (bits & SU_WEAPON)
2246 if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
2247 MSG_WriteShort (msg, stats[STAT_WEAPON]);
2249 MSG_WriteByte (msg, stats[STAT_WEAPON]);
2251 MSG_WriteShort (msg, stats[STAT_HEALTH]);
2252 MSG_WriteByte (msg, stats[STAT_AMMO]);
2253 MSG_WriteByte (msg, stats[STAT_SHELLS]);
2254 MSG_WriteByte (msg, stats[STAT_NAILS]);
2255 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
2256 MSG_WriteByte (msg, stats[STAT_CELLS]);
2257 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_QUOTH || IS_OLDNEXUIZ_DERIVED(gamemode))
2259 for (i = 0;i < 32;i++)
2260 if (stats[STAT_ACTIVEWEAPON] & (1<<i))
2262 MSG_WriteByte (msg, i);
2265 MSG_WriteByte (msg, stats[STAT_ACTIVEWEAPON]);
2266 if (bits & SU_VIEWZOOM)
2268 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
2269 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
2271 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
2276 void SV_FlushBroadcastMessages(void)
2280 if (sv.datagram.cursize <= 0)
2282 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2284 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])))
2286 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
2287 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
2289 SZ_Clear(&sv.datagram);
2292 static void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg, int maxsize, int maxsize2)
2294 // scan the splitpoints to find out how many we can fit in
2295 int numsegments, j, split;
2296 if (!client->unreliablemsg_splitpoints)
2298 // always accept the first one if it's within 1024 bytes, this ensures
2299 // that very big datagrams which are over the rate limit still get
2300 // through, just to keep it working
2301 for (numsegments = 1;numsegments < client->unreliablemsg_splitpoints;numsegments++)
2302 if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > maxsize)
2304 // the first segment gets an exemption from the rate limiting, otherwise
2305 // it could get dropped consistently due to a low rate limit
2306 if (numsegments == 1)
2308 // some will fit, so add the ones that will fit
2309 split = client->unreliablemsg_splitpoint[numsegments-1];
2310 // note this discards ones that were accepted by the segments scan but
2311 // can not fit, such as a really huge first one that will never ever
2312 // fit in a packet...
2313 if (msg->cursize + split <= maxsize)
2314 SZ_Write(msg, client->unreliablemsg.data, split);
2315 // remove the part we sent, keeping any remaining data
2316 client->unreliablemsg.cursize -= split;
2317 if (client->unreliablemsg.cursize > 0)
2318 memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
2319 // adjust remaining splitpoints
2320 client->unreliablemsg_splitpoints -= numsegments;
2321 for (j = 0;j < client->unreliablemsg_splitpoints;j++)
2322 client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
2326 =======================
2327 SV_SendClientDatagram
2328 =======================
2330 static void SV_SendClientDatagram (client_t *client)
2332 int clientrate, maxrate, maxsize, maxsize2, downloadsize;
2334 int stats[MAX_CL_STATS];
2335 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE];
2338 // obey rate limit by limiting packet frequency if the packet size
2340 // (usually this is caused by reliable messages)
2341 if (!NetConn_CanSend(client->netconnection))
2344 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
2345 maxrate = max(NET_MINRATE, sv_maxrate.integer);
2346 if (sv_maxrate.integer != maxrate)
2347 Cvar_SetValueQuick(&sv_maxrate, maxrate);
2349 // clientrate determines the 'cleartime' of a packet
2350 // (how long to wait before sending another, based on this packet's size)
2351 clientrate = bound(NET_MINRATE, client->rate, maxrate);
2353 switch (sv.protocol)
2355 case PROTOCOL_QUAKE:
2356 case PROTOCOL_QUAKEDP:
2357 case PROTOCOL_NEHAHRAMOVIE:
2358 case PROTOCOL_NEHAHRABJP:
2359 case PROTOCOL_NEHAHRABJP2:
2360 case PROTOCOL_NEHAHRABJP3:
2361 case PROTOCOL_QUAKEWORLD:
2362 // no packet size limit support on Quake protocols because it just
2363 // causes missing entities/effects
2364 // packets are simply sent less often to obey the rate limit
2368 case PROTOCOL_DARKPLACES1:
2369 case PROTOCOL_DARKPLACES2:
2370 case PROTOCOL_DARKPLACES3:
2371 case PROTOCOL_DARKPLACES4:
2372 // no packet size limit support on DP1-4 protocols because they kick
2373 // the client off if they overflow, and miss effects
2374 // packets are simply sent less often to obey the rate limit
2375 maxsize = sizeof(sv_sendclientdatagram_buf);
2376 maxsize2 = sizeof(sv_sendclientdatagram_buf);
2379 // DP5 and later protocols support packet size limiting which is a
2380 // better method than limiting packet frequency as QW does
2382 // at very low rates (or very small sys_ticrate) the packet size is
2383 // not reduced below 128, but packets may be sent less often
2385 // how long are bursts?
2386 timedelta = host_client->rate_burstsize / (double)client->rate;
2388 // how much of the burst do we keep reserved?
2389 timedelta *= 1 - net_burstreserve.value;
2391 // only try to use excess time
2392 timedelta = bound(0, realtime - host_client->netconnection->cleartime, timedelta);
2394 // but we know next packet will be in sys_ticrate, so we can use up THAT bandwidth
2395 timedelta += sys_ticrate.value;
2397 // note: packet overhead (not counted in maxsize) is 28 bytes
2398 maxsize = (int)(clientrate * timedelta) - 28;
2400 // put it in sound bounds
2401 maxsize = bound(128, maxsize, 1400);
2404 // csqc entities can easily exceed 128 bytes, so disable throttling in
2405 // mods that use csqc (they are likely to use less bandwidth anyway)
2406 if((net_usesizelimit.integer == 1) ? (sv.csqc_progsize > 0) : (net_usesizelimit.integer < 1))
2412 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
2414 // for good singleplayer, send huge packets
2415 maxsize = sizeof(sv_sendclientdatagram_buf);
2416 maxsize2 = sizeof(sv_sendclientdatagram_buf);
2417 // never limit frequency in singleplayer
2418 clientrate = 1000000000;
2421 // while downloading, limit entity updates to half the packet
2422 // (any leftover space will be used for downloading)
2423 if (host_client->download_file)
2426 msg.data = sv_sendclientdatagram_buf;
2427 msg.maxsize = sizeof(sv_sendclientdatagram_buf);
2429 msg.allowoverflow = false;
2431 if (host_client->begun)
2433 // the player is in the game
2434 MSG_WriteByte (&msg, svc_time);
2435 MSG_WriteFloat (&msg, sv.time);
2437 // add the client specific data to the datagram
2438 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
2439 // now update the stats[] array using any registered custom fields
2440 VM_SV_UpdateCustomStats(client, client->edict, &msg, stats);
2441 // set host_client->statsdeltabits
2442 Protocol_UpdateClientStats (stats);
2444 // add as many queued unreliable messages (effects) as we can fit
2445 // limit effects to half of the remaining space
2446 if (client->unreliablemsg.cursize)
2447 SV_WriteUnreliableMessages (client, &msg, maxsize/2, maxsize2);
2449 // now write as many entities as we can fit, and also sends stats
2450 SV_WriteEntitiesToClient (client, client->edict, &msg, maxsize);
2452 else if (realtime > client->keepalivetime)
2454 // the player isn't totally in the game yet
2455 // send small keepalive messages if too much time has passed
2456 // (may also be sending downloads)
2457 client->keepalivetime = realtime + 5;
2458 MSG_WriteChar (&msg, svc_nop);
2461 // if a download is active, see if there is room to fit some download data
2463 downloadsize = min(maxsize*2,maxsize2) - msg.cursize - 7;
2464 if (host_client->download_file && host_client->download_started && downloadsize > 0)
2466 fs_offset_t downloadstart;
2467 unsigned char data[1400];
2468 downloadstart = FS_Tell(host_client->download_file);
2469 downloadsize = min(downloadsize, (int)sizeof(data));
2470 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
2471 // note this sends empty messages if at the end of the file, which is
2472 // necessary to keep the packet loss logic working
2473 // (the last blocks may be lost and need to be re-sent, and that will
2474 // only occur if the client acks the empty end messages, revealing
2475 // a gap in the download progress, causing the last blocks to be
2477 MSG_WriteChar (&msg, svc_downloaddata);
2478 MSG_WriteLong (&msg, downloadstart);
2479 MSG_WriteShort (&msg, downloadsize);
2480 if (downloadsize > 0)
2481 SZ_Write (&msg, data, downloadsize);
2484 // reliable only if none is in progress
2485 if(client->sendsignon != 2 && !client->netconnection->sendMessageLength)
2486 SV_WriteDemoMessage(client, &(client->netconnection->message), false);
2488 SV_WriteDemoMessage(client, &msg, false);
2490 // send the datagram
2491 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate, client->rate_burstsize, client->sendsignon == 2);
2492 if (client->sendsignon == 1 && !client->netconnection->message.cursize)
2493 client->sendsignon = 2; // prevent reliable until client sends prespawn (this is the keepalive phase)
2497 =======================
2498 SV_UpdateToReliableMessages
2499 =======================
2501 static void SV_UpdateToReliableMessages (void)
2503 prvm_prog_t *prog = SVVM_prog;
2511 // check for changes to be sent over the reliable streams
2512 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2514 // update the host_client fields we care about according to the entity fields
2515 host_client->edict = PRVM_EDICT_NUM(i+1);
2518 name = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, netname));
2521 // always point the string back at host_client->name to keep it safe
2522 //strlcpy (host_client->name, name, sizeof (host_client->name));
2523 if (name != host_client->name) // prevent buffer overlap SIGABRT on Mac OSX
2524 strlcpy (host_client->name, name, sizeof (host_client->name));
2525 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
2526 if (strcmp(host_client->old_name, host_client->name))
2528 if (host_client->begun)
2529 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
2530 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
2531 // send notification to all clients
2532 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
2533 MSG_WriteByte (&sv.reliable_datagram, i);
2534 MSG_WriteString (&sv.reliable_datagram, host_client->name);
2535 SV_WriteNetnameIntoDemo(host_client);
2538 // DP_SV_CLIENTCOLORS
2539 host_client->colors = (int)PRVM_serveredictfloat(host_client->edict, clientcolors);
2540 if (host_client->old_colors != host_client->colors)
2542 host_client->old_colors = host_client->colors;
2543 // send notification to all clients
2544 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2545 MSG_WriteByte (&sv.reliable_datagram, i);
2546 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
2549 // NEXUIZ_PLAYERMODEL
2550 model = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, playermodel));
2553 // always point the string back at host_client->name to keep it safe
2554 //strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
2555 if (model != host_client->playermodel) // prevent buffer overlap SIGABRT on Mac OSX
2556 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
2557 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
2559 // NEXUIZ_PLAYERSKIN
2560 skin = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, playerskin));
2563 // always point the string back at host_client->name to keep it safe
2564 //strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
2565 if (skin != host_client->playerskin) // prevent buffer overlap SIGABRT on Mac OSX
2566 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
2567 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
2569 // TODO: add an extension name for this [1/17/2008 Black]
2570 clientcamera = PRVM_serveredictedict(host_client->edict, clientcamera);
2571 if (clientcamera > 0)
2573 int oldclientcamera = host_client->clientcamera;
2574 if (clientcamera >= prog->max_edicts || PRVM_EDICT_NUM(clientcamera)->priv.required->free)
2575 clientcamera = PRVM_NUM_FOR_EDICT(host_client->edict);
2576 host_client->clientcamera = clientcamera;
2578 if (oldclientcamera != host_client->clientcamera && host_client->netconnection)
2580 MSG_WriteByte(&host_client->netconnection->message, svc_setview);
2581 MSG_WriteShort(&host_client->netconnection->message, host_client->clientcamera);
2586 host_client->frags = (int)PRVM_serveredictfloat(host_client->edict, frags);
2587 if(IS_OLDNEXUIZ_DERIVED(gamemode))
2588 if(!host_client->begun && host_client->netconnection)
2589 host_client->frags = -666;
2590 if (host_client->old_frags != host_client->frags)
2592 host_client->old_frags = host_client->frags;
2593 // send notification to all clients
2594 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
2595 MSG_WriteByte (&sv.reliable_datagram, i);
2596 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
2600 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
2601 if (client->netconnection && (client->begun || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet
2602 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
2604 SZ_Clear (&sv.reliable_datagram);
2609 =======================
2610 SV_SendClientMessages
2611 =======================
2613 void SV_SendClientMessages(void)
2615 int i, prepared = false;
2617 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2618 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
2620 SV_FlushBroadcastMessages();
2622 // update frags, names, etc
2623 SV_UpdateToReliableMessages();
2625 // build individual updates
2626 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2628 if (!host_client->active)
2630 if (!host_client->netconnection)
2633 if (host_client->netconnection->message.overflowed)
2635 SV_DropClient (true); // if the message couldn't send, kick off
2642 // only prepare entities once per frame
2643 SV_PrepareEntitiesForSending();
2645 SV_SendClientDatagram(host_client);
2648 // clear muzzle flashes
2652 static void SV_StartDownload_f(cmd_state_t *cmd)
2654 if (host_client->download_file)
2655 host_client->download_started = true;
2659 * Compression extension negotiation:
2662 * cl_serverextension_download 2
2665 * download <filename> <list of zero or more suppported compressions in order of preference>
2667 * download maps/map1.bsp lzo deflate huffman
2670 * cl_downloadbegin <compressed size> <filename> <compression method actually used>
2672 * cl_downloadbegin 123456 maps/map1.bsp deflate
2674 * The server may choose not to compress the file by sending no compression name, like:
2675 * cl_downloadbegin 345678 maps/map1.bsp
2677 * NOTE: the "download" command may only specify compression algorithms if
2678 * cl_serverextension_download is 2!
2679 * If cl_serverextension_download has a different value, the client must
2680 * assume this extension is not supported!
2683 static void Download_CheckExtensions(cmd_state_t *cmd)
2686 int argc = Cmd_Argc(cmd);
2688 // first reset them all
2689 host_client->download_deflate = false;
2691 for(i = 2; i < argc; ++i)
2693 if(!strcmp(Cmd_Argv(cmd, i), "deflate"))
2695 host_client->download_deflate = true;
2701 static void SV_Download_f(cmd_state_t *cmd)
2703 const char *whichpack, *whichpack2, *extension;
2704 qboolean is_csqc; // so we need to check only once
2706 if (Cmd_Argc(cmd) < 2)
2708 SV_ClientPrintf("usage: download <filename> {<extensions>}*\n");
2709 SV_ClientPrintf(" supported extensions: deflate\n");
2713 if (FS_CheckNastyPath(Cmd_Argv(cmd, 1), false))
2715 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(cmd, 1));
2719 if (host_client->download_file)
2721 // at this point we'll assume the previous download should be aborted
2722 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
2723 Host_ClientCommands("\nstopdownload\n");
2725 // close the file and reset variables
2726 FS_Close(host_client->download_file);
2727 host_client->download_file = NULL;
2728 host_client->download_name[0] = 0;
2729 host_client->download_expectedposition = 0;
2730 host_client->download_started = false;
2733 is_csqc = (sv.csqc_progname[0] && strcmp(Cmd_Argv(cmd, 1), sv.csqc_progname) == 0);
2735 if (!sv_allowdownloads.integer && !is_csqc)
2737 SV_ClientPrintf("Downloads are disabled on this server\n");
2738 Host_ClientCommands("\nstopdownload\n");
2742 Download_CheckExtensions(cmd);
2744 strlcpy(host_client->download_name, Cmd_Argv(cmd, 1), sizeof(host_client->download_name));
2745 extension = FS_FileExtension(host_client->download_name);
2747 // host_client is asking to download a specified file
2748 if (developer_extra.integer)
2749 Con_DPrintf("Download request for %s by %s\n", host_client->download_name, host_client->name);
2753 char extensions[MAX_QPATH]; // make sure this can hold all extensions
2754 extensions[0] = '\0';
2756 if(host_client->download_deflate)
2757 strlcat(extensions, " deflate", sizeof(extensions));
2759 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
2761 if(host_client->download_deflate && svs.csqc_progdata_deflated)
2762 host_client->download_file = FS_FileFromData(svs.csqc_progdata_deflated, svs.csqc_progsize_deflated, true);
2764 host_client->download_file = FS_FileFromData(svs.csqc_progdata, sv.csqc_progsize, true);
2766 // no, no space is needed between %s and %s :P
2767 Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions);
2769 host_client->download_expectedposition = 0;
2770 host_client->download_started = false;
2771 host_client->sendsignon = true; // make sure this message is sent
2775 if (!FS_FileExists(host_client->download_name))
2777 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);
2778 Host_ClientCommands("\nstopdownload\n");
2782 // check if the user is trying to download part of registered Quake(r)
2783 whichpack = FS_WhichPack(host_client->download_name);
2784 whichpack2 = FS_WhichPack("gfx/pop.lmp");
2785 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
2787 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);
2788 Host_ClientCommands("\nstopdownload\n");
2792 // check if the server has forbidden archive downloads entirely
2793 if (!sv_allowdownloads_inarchive.integer)
2795 whichpack = FS_WhichPack(host_client->download_name);
2798 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);
2799 Host_ClientCommands("\nstopdownload\n");
2804 if (!sv_allowdownloads_config.integer)
2806 if (!strcasecmp(extension, "cfg"))
2808 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);
2809 Host_ClientCommands("\nstopdownload\n");
2814 if (!sv_allowdownloads_dlcache.integer)
2816 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
2818 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);
2819 Host_ClientCommands("\nstopdownload\n");
2824 if (!sv_allowdownloads_archive.integer)
2826 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
2828 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);
2829 Host_ClientCommands("\nstopdownload\n");
2834 host_client->download_file = FS_OpenVirtualFile(host_client->download_name, true);
2835 if (!host_client->download_file)
2837 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
2838 Host_ClientCommands("\nstopdownload\n");
2842 if (FS_FileSize(host_client->download_file) > 1<<30)
2844 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
2845 Host_ClientCommands("\nstopdownload\n");
2846 FS_Close(host_client->download_file);
2847 host_client->download_file = NULL;
2851 if (FS_FileSize(host_client->download_file) < 0)
2853 SV_ClientPrintf("Download rejected: file \"%s\" is not a regular file\n", host_client->download_name);
2854 Host_ClientCommands("\nstopdownload\n");
2855 FS_Close(host_client->download_file);
2856 host_client->download_file = NULL;
2860 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
2863 * we can only do this if we would actually deflate on the fly
2864 * which we do not (yet)!
2866 char extensions[MAX_QPATH]; // make sure this can hold all extensions
2867 extensions[0] = '\0';
2869 if(host_client->download_deflate)
2870 strlcat(extensions, " deflate", sizeof(extensions));
2872 // no, no space is needed between %s and %s :P
2873 Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions);
2876 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
2878 host_client->download_expectedposition = 0;
2879 host_client->download_started = false;
2880 host_client->sendsignon = true; // make sure this message is sent
2882 // the rest of the download process is handled in SV_SendClientDatagram
2883 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
2885 // no svc_downloaddata messages will be sent until sv_startdownload is
2886 // sent by the client
2890 ==============================================================================
2894 ==============================================================================
2903 int SV_ModelIndex(const char *s, int precachemode)
2905 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);
2906 char filename[MAX_QPATH];
2910 //if (precachemode == 2)
2912 strlcpy(filename, s, sizeof(filename));
2913 for (i = 2;i < limit;i++)
2915 if (!sv.model_precache[i][0])
2919 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))
2921 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
2924 if (precachemode == 1)
2925 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
2926 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
2927 if (sv.state == ss_loading)
2929 // running from SV_SpawnServer which is launched from the client console command interpreter
2930 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.worldname : NULL);
2936 // 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
2937 sv.models[i] = Mod_FindName (sv.model_precache[i], s[0] == '*' ? sv.worldname : NULL);
2941 // running single threaded, so we can load the model here
2942 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.worldname : NULL);
2944 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
2945 MSG_WriteShort(&sv.reliable_datagram, i);
2946 MSG_WriteString(&sv.reliable_datagram, filename);
2950 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
2953 if (!strcmp(sv.model_precache[i], filename))
2956 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
2966 int SV_SoundIndex(const char *s, int precachemode)
2968 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);
2969 char filename[MAX_QPATH];
2973 //if (precachemode == 2)
2975 strlcpy(filename, s, sizeof(filename));
2976 for (i = 1;i < limit;i++)
2978 if (!sv.sound_precache[i][0])
2982 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))
2984 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
2987 if (precachemode == 1)
2988 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
2989 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
2990 if (sv.state != ss_loading)
2992 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
2993 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
2994 MSG_WriteString(&sv.reliable_datagram, filename);
2998 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
3001 if (!strcmp(sv.sound_precache[i], filename))
3004 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
3010 SV_ParticleEffectIndex
3014 int SV_ParticleEffectIndex(const char *name)
3016 int i, argc, linenumber, effectnameindex;
3018 fs_offset_t filesize;
3019 unsigned char *filedata;
3021 const char *textstart;
3022 //const char *textend;
3023 char argv[16][1024];
3024 char filename[MAX_QPATH];
3025 if (!sv.particleeffectnamesloaded)
3027 sv.particleeffectnamesloaded = true;
3028 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
3029 for (i = 0;i < EFFECT_TOTAL;i++)
3030 strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
3031 for (filepass = 0;;filepass++)
3034 dpsnprintf(filename, sizeof(filename), "effectinfo.txt");
3035 else if (filepass == 1)
3036 dpsnprintf(filename, sizeof(filename), "%s_effectinfo.txt", sv.worldnamenoextension);
3039 filedata = FS_LoadFile(filename, tempmempool, true, &filesize);
3042 textstart = (const char *)filedata;
3043 //textend = (const char *)filedata + filesize;
3045 for (linenumber = 1;;linenumber++)
3050 if (!COM_ParseToken_Simple(&text, true, false, true) || !strcmp(com_token, "\n"))
3054 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
3058 if (com_token[0] == 0)
3059 break; // if the loop exited and it's not a \n, it's EOF
3062 if (!strcmp(argv[0], "effect"))
3066 for (effectnameindex = 1;effectnameindex < MAX_PARTICLEEFFECTNAME;effectnameindex++)
3068 if (sv.particleeffectname[effectnameindex][0])
3070 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
3075 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
3079 // if we run out of names, abort
3080 if (effectnameindex == MAX_PARTICLEEFFECTNAME)
3082 Con_Printf("%s:%i: too many effects!\n", filename, linenumber);
3091 // search for the name
3092 for (effectnameindex = 1;effectnameindex < MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
3093 if (!strcmp(sv.particleeffectname[effectnameindex], name))
3094 return effectnameindex;
3095 // return 0 if we couldn't find it
3099 dp_model_t *SV_GetModelByIndex(int modelindex)
3101 return (modelindex > 0 && modelindex < MAX_MODELS) ? sv.models[modelindex] : NULL;
3104 dp_model_t *SV_GetModelFromEdict(prvm_edict_t *ed)
3106 prvm_prog_t *prog = SVVM_prog;
3108 if (!ed || ed->priv.server->free)
3110 modelindex = (int)PRVM_serveredictfloat(ed, modelindex);
3111 return (modelindex > 0 && modelindex < MAX_MODELS) ? sv.models[modelindex] : NULL;
3120 static void SV_CreateBaseline (void)
3122 prvm_prog_t *prog = SVVM_prog;
3123 int i, entnum, large;
3124 prvm_edict_t *svent;
3126 // LadyHavoc: clear *all* baselines (not just active ones)
3127 for (entnum = 0;entnum < prog->max_edicts;entnum++)
3129 // get the current server version
3130 svent = PRVM_EDICT_NUM(entnum);
3132 // LadyHavoc: always clear state values, whether the entity is in use or not
3133 svent->priv.server->baseline = defaultstate;
3135 if (svent->priv.server->free)
3137 if (entnum > svs.maxclients && !PRVM_serveredictfloat(svent, modelindex))
3140 // create entity baseline
3141 VectorCopy (PRVM_serveredictvector(svent, origin), svent->priv.server->baseline.origin);
3142 VectorCopy (PRVM_serveredictvector(svent, angles), svent->priv.server->baseline.angles);
3143 svent->priv.server->baseline.frame = (int)PRVM_serveredictfloat(svent, frame);
3144 svent->priv.server->baseline.skin = (int)PRVM_serveredictfloat(svent, skin);
3145 if (entnum > 0 && entnum <= svs.maxclients)
3147 svent->priv.server->baseline.colormap = entnum;
3148 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
3152 svent->priv.server->baseline.colormap = 0;
3153 svent->priv.server->baseline.modelindex = (int)PRVM_serveredictfloat(svent, modelindex);
3157 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
3160 if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
3164 // add to the message
3166 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
3168 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
3169 MSG_WriteShort (&sv.signon, entnum);
3173 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
3174 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
3176 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
3178 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
3179 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
3183 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
3184 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
3186 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
3187 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
3188 for (i=0 ; i<3 ; i++)
3190 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
3191 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
3200 Load csprogs.dat and comperss it so it doesn't need to be
3201 reloaded on request.
3204 static void SV_Prepare_CSQC(void)
3206 fs_offset_t progsize;
3208 if(svs.csqc_progdata)
3210 Con_DPrintf("Unloading old CSQC data.\n");
3211 Mem_Free(svs.csqc_progdata);
3212 if(svs.csqc_progdata_deflated)
3213 Mem_Free(svs.csqc_progdata_deflated);
3216 svs.csqc_progdata = NULL;
3217 svs.csqc_progdata_deflated = NULL;
3219 sv.csqc_progname[0] = 0;
3220 svs.csqc_progdata = FS_LoadFile(csqc_progname.string, sv_mempool, false, &progsize);
3224 size_t deflated_size;
3226 sv.csqc_progsize = (int)progsize;
3227 sv.csqc_progcrc = CRC_Block(svs.csqc_progdata, progsize);
3228 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
3229 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
3231 Con_DPrint("Compressing csprogs.dat\n");
3232 //unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflated_size, int level, mempool_t *mempool);
3233 svs.csqc_progdata_deflated = FS_Deflate(svs.csqc_progdata, progsize, &deflated_size, -1, sv_mempool);
3234 svs.csqc_progsize_deflated = (int)deflated_size;
3235 if(svs.csqc_progdata_deflated)
3237 Con_DPrintf("Deflated: %g%%\n", 100.0 - 100.0 * (deflated_size / (float)progsize));
3238 Con_DPrintf("Uncompressed: %u\nCompressed: %u\n", (unsigned)sv.csqc_progsize, (unsigned)svs.csqc_progsize_deflated);
3241 Con_DPrintf("Cannot compress - need zlib for this. Using uncompressed progs only.\n");
3249 Grabs the current state of each client for saving across the
3250 transition to another level
3253 void SV_SaveSpawnparms (void)
3255 prvm_prog_t *prog = SVVM_prog;
3258 svs.serverflags = (int)PRVM_serverglobalfloat(serverflags);
3260 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
3262 if (!host_client->active)
3265 // call the progs to get default spawn parms for the new client
3266 PRVM_serverglobalfloat(time) = sv.time;
3267 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
3268 prog->ExecuteProgram(prog, PRVM_serverfunction(SetChangeParms), "QC function SetChangeParms is missing");
3269 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
3270 host_client->spawn_parms[j] = (&PRVM_serverglobalfloat(parm1))[j];
3278 This is called at the start of each level
3282 void SV_SpawnServer (const char *server)
3284 prvm_prog_t *prog = SVVM_prog;
3288 dp_model_t *worldmodel;
3289 char modelname[sizeof(sv.worldname)];
3292 Con_DPrintf("SpawnServer: %s\n", server);
3294 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
3296 if (!FS_FileExists(modelname))
3298 dpsnprintf (modelname, sizeof(modelname), "maps/%s", server);
3299 if (!FS_FileExists(modelname))
3301 Con_Printf("SpawnServer: no map file named maps/%s.bsp\n", server);
3306 // SV_LockThreadMutex();
3308 if(cls.state == ca_dedicated)
3309 Sys_MakeProcessNice();
3311 if (cls.state != ca_dedicated)
3313 SCR_BeginLoadingPlaque(false);
3319 World_End(&sv.world);
3320 if(PRVM_serverfunction(SV_Shutdown))
3322 func_t s = PRVM_serverfunction(SV_Shutdown);
3323 PRVM_serverglobalfloat(time) = sv.time;
3324 PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
3325 prog->ExecuteProgram(prog, s,"SV_Shutdown() required");
3329 // free q3 shaders so that any newly downloaded shaders will be active
3330 Mod_FreeQ3Shaders();
3332 worldmodel = Mod_ForName(modelname, false, developer.integer > 0, NULL);
3333 if (!worldmodel || !worldmodel->TraceBox)
3335 Con_Printf("Couldn't load map %s\n", modelname);
3337 if(cls.state == ca_dedicated)
3338 Sys_MakeProcessMean();
3340 // SV_UnlockThreadMutex();
3345 Collision_Cache_Reset(true);
3347 // let's not have any servers with no name
3348 if (hostname.string[0] == 0)
3349 Cvar_SetQuick(&hostname, "UNNAMED");
3350 scr_centertime_off = 0;
3352 svs.changelevel_issued = false; // now safe to issue another
3354 // make the map a required file for clients
3355 Curl_ClearRequirements();
3356 Curl_RequireFile(modelname);
3359 // tell all connected clients that we are going to a new level
3364 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
3366 if (client->netconnection)
3368 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
3369 MSG_WriteString(&client->netconnection->message, "reconnect\n");
3376 NetConn_OpenServerPorts(true);
3380 // make cvars consistant
3383 Cvar_SetValueQuick(&deathmatch, 0);
3384 // LadyHavoc: it can be useful to have skills outside the range 0-3...
3385 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
3386 //Cvar_SetValue ("skill", (float)current_skill);
3387 current_skill = (int)(skill.value + 0.5);
3390 // set up the new server
3392 memset (&sv, 0, sizeof(sv));
3393 // if running a local client, make sure it doesn't try to access the last
3394 // level's data which is no longer valiud
3397 Cvar_SetValueQuick(&halflifebsp, worldmodel->brush.ishlbsp);
3398 Cvar_SetValueQuick(&sv_mapformat_is_quake2, worldmodel->brush.isq2bsp);
3399 Cvar_SetValueQuick(&sv_mapformat_is_quake3, worldmodel->brush.isq3bsp);
3401 if(*sv_random_seed.string)
3403 srand(sv_random_seed.integer);
3404 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);
3411 // set level base name variables for later use
3412 strlcpy (sv.name, server, sizeof (sv.name));
3413 strlcpy(sv.worldname, modelname, sizeof(sv.worldname));
3414 FS_StripExtension(sv.worldname, sv.worldnamenoextension, sizeof(sv.worldnamenoextension));
3415 strlcpy(sv.worldbasename, !strncmp(sv.worldnamenoextension, "maps/", 5) ? sv.worldnamenoextension + 5 : sv.worldnamenoextension, sizeof(sv.worldbasename));
3416 //Cvar_SetQuick(&sv_worldmessage, sv.worldmessage); // set later after QC is spawned
3417 Cvar_SetQuick(&sv_worldname, sv.worldname);
3418 Cvar_SetQuick(&sv_worldnamenoextension, sv.worldnamenoextension);
3419 Cvar_SetQuick(&sv_worldbasename, sv.worldbasename);
3421 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
3422 if (sv.protocol == PROTOCOL_UNKNOWN)
3425 Protocol_Names(buffer, sizeof(buffer));
3426 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
3427 sv.protocol = PROTOCOL_QUAKE;
3430 // load progs to get entity field count
3431 //PR_LoadProgs ( sv_progs.string );
3433 sv.datagram.maxsize = sizeof(sv.datagram_buf);
3434 sv.datagram.cursize = 0;
3435 sv.datagram.data = sv.datagram_buf;
3437 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
3438 sv.reliable_datagram.cursize = 0;
3439 sv.reliable_datagram.data = sv.reliable_datagram_buf;
3441 sv.signon.maxsize = sizeof(sv.signon_buf);
3442 sv.signon.cursize = 0;
3443 sv.signon.data = sv.signon_buf;
3445 // leave slots at start for clients only
3446 //prog->num_edicts = svs.maxclients+1;
3448 sv.state = ss_loading;
3449 prog->allowworldwrites = true;
3455 worldmodel->used = true;
3457 sv.worldmodel = worldmodel;
3458 sv.models[1] = sv.worldmodel;
3461 // clear world interaction links
3463 World_SetSize(&sv.world, sv.worldname, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs, prog);
3464 World_Start(&sv.world);
3466 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
3468 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
3469 strlcpy(sv.model_precache[1], sv.worldname, sizeof(sv.model_precache[1]));
3470 for (i = 1;i < sv.worldmodel->brush.numsubmodels && i+1 < MAX_MODELS;i++)
3472 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
3473 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, sv.worldname);
3475 if(i < sv.worldmodel->brush.numsubmodels)
3476 Con_Printf("Too many submodels (MAX_MODELS is %i)\n", MAX_MODELS);
3479 // load the rest of the entities
3481 // AK possible hack since num_edicts is still 0
3482 ent = PRVM_EDICT_NUM(0);
3483 memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
3484 ent->priv.server->free = false;
3485 PRVM_serveredictstring(ent, model) = PRVM_SetEngineString(prog, sv.worldname);
3486 PRVM_serveredictfloat(ent, modelindex) = 1; // world model
3487 PRVM_serveredictfloat(ent, solid) = SOLID_BSP;
3488 PRVM_serveredictfloat(ent, movetype) = MOVETYPE_PUSH;
3489 VectorCopy(sv.world.mins, PRVM_serveredictvector(ent, mins));
3490 VectorCopy(sv.world.maxs, PRVM_serveredictvector(ent, maxs));
3491 VectorCopy(sv.world.mins, PRVM_serveredictvector(ent, absmin));
3492 VectorCopy(sv.world.maxs, PRVM_serveredictvector(ent, absmax));
3495 PRVM_serverglobalfloat(coop) = coop.integer;
3497 PRVM_serverglobalfloat(deathmatch) = deathmatch.integer;
3499 PRVM_serverglobalstring(mapname) = PRVM_SetEngineString(prog, sv.name);
3501 // serverflags are for cross level information (sigils)
3502 PRVM_serverglobalfloat(serverflags) = svs.serverflags;
3504 // we need to reset the spawned flag on all connected clients here so that
3505 // their thinks don't run during startup (before PutClientInServer)
3506 // we also need to set up the client entities now
3507 // and we need to set the ->edict pointers to point into the progs edicts
3508 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
3510 host_client->begun = false;
3511 host_client->edict = PRVM_EDICT_NUM(i + 1);
3512 PRVM_ED_ClearEdict(prog, host_client->edict);
3515 // load replacement entity file if found
3516 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.ent", sv.worldnamenoextension), tempmempool, true, NULL)))
3518 Con_Printf("Loaded %s.ent\n", sv.worldnamenoextension);
3519 PRVM_ED_LoadFromFile(prog, entities);
3523 PRVM_ED_LoadFromFile(prog, sv.worldmodel->brush.entities);
3526 // LadyHavoc: clear world angles (to fix e3m3.bsp)
3527 VectorClear(PRVM_serveredictvector(prog->edicts, angles));
3529 // all setup is completed, any further precache statements are errors
3530 // sv.state = ss_active; // LadyHavoc: workaround for svc_precache bug
3531 prog->allowworldwrites = false;
3533 // run two frames to allow everything to settle
3535 for (i = 0;i < sv_init_frame_count.integer;i++)
3541 // Once all init frames have been run, we consider svqc code fully initialized.
3542 prog->inittime = realtime;
3544 if (cls.state == ca_dedicated)
3547 // create a baseline for more efficient communications
3548 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)
3549 SV_CreateBaseline ();
3551 sv.state = ss_active; // LadyHavoc: workaround for svc_precache bug
3553 // send serverinfo to all connected clients, and set up botclients coming back from a level change
3554 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
3556 host_client->clientconnectcalled = false; // do NOT call ClientDisconnect if he drops before ClientConnect!
3557 if (!host_client->active)
3559 if (host_client->netconnection)
3560 SV_SendServerinfo(host_client);
3564 // if client is a botclient coming from a level change, we need to
3565 // set up client info that normally requires networking
3567 // copy spawn parms out of the client_t
3568 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
3569 (&PRVM_serverglobalfloat(parm1))[j] = host_client->spawn_parms[j];
3571 // call the spawn function
3572 host_client->clientconnectcalled = true;
3573 PRVM_serverglobalfloat(time) = sv.time;
3574 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
3575 prog->ExecuteProgram(prog, PRVM_serverfunction(ClientConnect), "QC function ClientConnect is missing");
3576 prog->ExecuteProgram(prog, PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing");
3577 host_client->begun = true;
3581 // update the map title cvar
3582 strlcpy(sv.worldmessage, PRVM_GetString(prog, PRVM_serveredictstring(prog->edicts, message)), sizeof(sv.worldmessage)); // map title (not related to filename)
3583 Cvar_SetQuick(&sv_worldmessage, sv.worldmessage);
3585 Con_DPrint("Server spawned.\n");
3586 NetConn_Heartbeat (2);
3588 if(cls.state == ca_dedicated)
3589 Sys_MakeProcessMean();
3591 // SV_UnlockThreadMutex();
3594 /////////////////////////////////////////////////////
3597 static void SVVM_begin_increase_edicts(prvm_prog_t *prog)
3599 // links don't survive the transition, so unlink everything
3600 World_UnlinkAll(&sv.world);
3603 static void SVVM_end_increase_edicts(prvm_prog_t *prog)
3608 // link every entity except world
3609 for (i = 1, ent = prog->edicts;i < prog->num_edicts;i++, ent++)
3610 if (!ent->priv.server->free && !VectorCompare(PRVM_serveredictvector(ent, absmin), PRVM_serveredictvector(ent, absmax)))
3614 static void SVVM_init_edict(prvm_prog_t *prog, prvm_edict_t *e)
3616 // LadyHavoc: for consistency set these here
3617 int num = PRVM_NUM_FOR_EDICT(e) - 1;
3619 e->priv.server->move = false; // don't move on first frame
3621 if (num >= 0 && num < svs.maxclients)
3623 // set colormap and team on newly created player entity
3624 PRVM_serveredictfloat(e, colormap) = num + 1;
3625 PRVM_serveredictfloat(e, team) = (svs.clients[num].colors & 15) + 1;
3626 // set netname/clientcolors back to client values so that
3627 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
3629 PRVM_serveredictstring(e, netname) = PRVM_SetEngineString(prog, svs.clients[num].name);
3630 PRVM_serveredictfloat(e, clientcolors) = svs.clients[num].colors;
3631 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
3632 PRVM_serveredictstring(e, playermodel) = PRVM_SetEngineString(prog, svs.clients[num].playermodel);
3633 PRVM_serveredictstring(e, playerskin) = PRVM_SetEngineString(prog, svs.clients[num].playerskin);
3634 // Assign netaddress (IP Address, etc)
3635 if(svs.clients[num].netconnection != NULL)
3637 // Acquire Readable Address
3638 LHNETADDRESS_ToString(&svs.clients[num].netconnection->peeraddress, svs.clients[num].netaddress, sizeof(svs.clients[num].netaddress), false);
3639 PRVM_serveredictstring(e, netaddress) = PRVM_SetEngineString(prog, svs.clients[num].netaddress);
3642 PRVM_serveredictstring(e, netaddress) = PRVM_SetEngineString(prog, "null/botclient");
3643 if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.client_idfp[0])
3644 PRVM_serveredictstring(e, crypto_idfp) = PRVM_SetEngineString(prog, svs.clients[num].netconnection->crypto.client_idfp);
3646 PRVM_serveredictstring(e, crypto_idfp) = 0;
3647 PRVM_serveredictfloat(e, crypto_idfp_signed) = (svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.client_issigned);
3648 if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.client_keyfp[0])
3649 PRVM_serveredictstring(e, crypto_keyfp) = PRVM_SetEngineString(prog, svs.clients[num].netconnection->crypto.client_keyfp);
3651 PRVM_serveredictstring(e, crypto_keyfp) = 0;
3652 if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.server_keyfp[0])
3653 PRVM_serveredictstring(e, crypto_mykeyfp) = PRVM_SetEngineString(prog, svs.clients[num].netconnection->crypto.server_keyfp);
3655 PRVM_serveredictstring(e, crypto_mykeyfp) = 0;
3656 if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.use_aes)
3657 PRVM_serveredictstring(e, crypto_encryptmethod) = PRVM_SetEngineString(prog, "AES128");
3659 PRVM_serveredictstring(e, crypto_encryptmethod) = 0;
3660 if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated)
3661 PRVM_serveredictstring(e, crypto_signmethod) = PRVM_SetEngineString(prog, "HMAC-SHA256");
3663 PRVM_serveredictstring(e, crypto_signmethod) = 0;
3667 static void SVVM_free_edict(prvm_prog_t *prog, prvm_edict_t *ed)
3672 World_UnlinkEdict(ed); // unlink from world bsp
3674 PRVM_serveredictstring(ed, model) = 0;
3675 PRVM_serveredictfloat(ed, takedamage) = 0;
3676 PRVM_serveredictfloat(ed, modelindex) = 0;
3677 PRVM_serveredictfloat(ed, colormap) = 0;
3678 PRVM_serveredictfloat(ed, skin) = 0;
3679 PRVM_serveredictfloat(ed, frame) = 0;
3680 VectorClear(PRVM_serveredictvector(ed, origin));
3681 VectorClear(PRVM_serveredictvector(ed, angles));
3682 PRVM_serveredictfloat(ed, nextthink) = -1;
3683 PRVM_serveredictfloat(ed, solid) = 0;
3685 VM_RemoveEdictSkeleton(prog, ed);
3686 World_Physics_RemoveFromEntity(&sv.world, ed);
3687 World_Physics_RemoveJointFromEntity(&sv.world, ed);
3689 // make sure csqc networking is aware of the removed entity
3690 e = PRVM_NUM_FOR_EDICT(ed);
3691 sv.csqcentityversion[e] = 0;
3692 for (i = 0;i < svs.maxclients;i++)
3693 svs.clients[i].csqcentitysendflags[e] = 0xFFFFFF;
3696 static void SVVM_count_edicts(prvm_prog_t *prog)
3700 int active, models, solid, step;
3702 active = models = solid = step = 0;
3703 for (i=0 ; i<prog->num_edicts ; i++)
3705 ent = PRVM_EDICT_NUM(i);
3706 if (ent->priv.server->free)
3709 if (PRVM_serveredictfloat(ent, solid))
3711 if (PRVM_serveredictstring(ent, model))
3713 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_STEP)
3717 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
3718 Con_Printf("active :%3i\n", active);
3719 Con_Printf("view :%3i\n", models);
3720 Con_Printf("touch :%3i\n", solid);
3721 Con_Printf("step :%3i\n", step);
3724 static qboolean SVVM_load_edict(prvm_prog_t *prog, prvm_edict_t *ent)
3726 // remove things from different skill levels or deathmatch
3727 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
3729 if (deathmatch.integer)
3731 if (((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_DEATHMATCH))
3736 else if ((current_skill <= 0 && ((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_EASY ))
3737 || (current_skill == 1 && ((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_MEDIUM))
3738 || (current_skill >= 2 && ((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_HARD )))
3746 static void SV_VM_Setup(void)
3748 prvm_prog_t *prog = SVVM_prog;
3749 PRVM_Prog_Init(prog, &cmd_server);
3751 // allocate the mempools
3752 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
3753 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
3754 prog->builtins = vm_sv_builtins;
3755 prog->numbuiltins = vm_sv_numbuiltins;
3756 prog->max_edicts = 512;
3757 if (sv.protocol == PROTOCOL_QUAKE)
3758 prog->limit_edicts = 640; // before quake mission pack 1 this was 512
3759 else if (sv.protocol == PROTOCOL_QUAKEDP)
3760 prog->limit_edicts = 2048; // guessing
3761 else if (sv.protocol == PROTOCOL_NEHAHRAMOVIE)
3762 prog->limit_edicts = 2048; // guessing!
3763 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
3764 prog->limit_edicts = 4096; // guessing!
3766 prog->limit_edicts = MAX_EDICTS;
3767 prog->reserved_edicts = svs.maxclients;
3768 prog->edictprivate_size = sizeof(edict_engineprivate_t);
3769 prog->name = "server";
3770 prog->extensionstring = vm_sv_extensions;
3771 prog->loadintoworld = true;
3773 // all callbacks must be defined (pointers are not checked before calling)
3774 prog->begin_increase_edicts = SVVM_begin_increase_edicts;
3775 prog->end_increase_edicts = SVVM_end_increase_edicts;
3776 prog->init_edict = SVVM_init_edict;
3777 prog->free_edict = SVVM_free_edict;
3778 prog->count_edicts = SVVM_count_edicts;
3779 prog->load_edict = SVVM_load_edict;
3780 prog->init_cmd = SVVM_init_cmd;
3781 prog->reset_cmd = SVVM_reset_cmd;
3782 prog->error_cmd = Host_Error;
3783 prog->ExecuteProgram = SVVM_ExecuteProgram;
3785 PRVM_Prog_Load(prog, sv_progs.string, NULL, 0, SV_REQFUNCS, sv_reqfuncs, SV_REQFIELDS, sv_reqfields, SV_REQGLOBALS, sv_reqglobals);
3787 // some mods compiled with scrambling compilers lack certain critical
3788 // global names and field names such as "self" and "time" and "nextthink"
3789 // so we have to set these offsets manually, matching the entvars_t
3790 // but we only do this if the prog header crc matches, otherwise it's totally freeform
3791 if (prog->progs_crc == PROGHEADER_CRC || prog->progs_crc == PROGHEADER_CRC_TENEBRAE)
3793 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, modelindex);
3794 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, absmin);
3795 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, absmax);
3796 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ltime);
3797 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, movetype);
3798 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, solid);
3799 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, origin);
3800 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, oldorigin);
3801 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, velocity);
3802 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
3803 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, avelocity);
3804 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, punchangle);
3805 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
3806 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, model);
3807 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
3808 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, skin);
3809 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, effects);
3810 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, mins);
3811 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, maxs);
3812 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, size);
3813 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, touch);
3814 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, use);
3815 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
3816 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, blocked);
3817 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
3818 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
3819 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, health);
3820 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frags);
3821 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, weapon);
3822 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, weaponmodel);
3823 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, weaponframe);
3824 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, currentammo);
3825 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_shells);
3826 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_nails);
3827 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_rockets);
3828 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_cells);
3829 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, items);
3830 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, takedamage);
3831 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
3832 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, deadflag);
3833 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, view_ofs);
3834 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, button0);
3835 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, button1);
3836 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, button2);
3837 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, impulse);
3838 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, fixangle);
3839 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, v_angle);
3840 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, idealpitch);
3841 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, netname);
3842 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, enemy);
3843 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, flags);
3844 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, colormap);
3845 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, team);
3846 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, max_health);
3847 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, teleport_time);
3848 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, armortype);
3849 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, armorvalue);
3850 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, waterlevel);
3851 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, watertype);
3852 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
3853 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
3854 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, aiment);
3855 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, goalentity);
3856 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, spawnflags);
3857 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, target);
3858 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, targetname);
3859 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, dmg_take);
3860 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, dmg_save);
3861 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, dmg_inflictor);
3862 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, owner);
3863 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, movedir);
3864 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, message);
3865 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, sounds);
3866 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise);
3867 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise1);
3868 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise2);
3869 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise3);
3870 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
3871 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, other);
3872 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, world);
3873 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
3874 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, frametime);
3875 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, force_retouch);
3876 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, mapname);
3877 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, deathmatch);
3878 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, coop);
3879 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, teamplay);
3880 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, serverflags);
3881 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, total_secrets);
3882 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, total_monsters);
3883 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, found_secrets);
3884 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, killed_monsters);
3885 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm1);
3886 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm2);
3887 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm3);
3888 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm4);
3889 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm5);
3890 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm6);
3891 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm7);
3892 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm8);
3893 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm9);
3894 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm10);
3895 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm11);
3896 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm12);
3897 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm13);
3898 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm14);
3899 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm15);
3900 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm16);
3901 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
3902 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
3903 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
3904 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
3905 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
3906 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
3907 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
3908 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
3909 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
3910 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
3911 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
3912 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
3913 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, msg_entity);
3914 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, main);
3915 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, StartFrame);
3916 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, PlayerPreThink);
3917 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, PlayerPostThink);
3918 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, ClientKill);
3919 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, ClientConnect);
3920 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, PutClientInServer);
3921 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, ClientDisconnect);
3922 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, SetNewParms);
3923 // PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, SetChangeParms);
3926 Con_DPrintf("%s: %s system vars have been modified (CRC %i != engine %i), will not load in other engines\n", prog->name, sv_progs.string, prog->progs_crc, PROGHEADER_CRC);
3928 // OP_STATE is always supported on server because we add fields/globals for it
3929 prog->flag |= PRVM_OP_STATE;
3931 VM_CustomStats_Clear();//[515]: csqc
3936 extern cvar_t host_maxwait;
3937 extern cvar_t host_framerate;
3938 static int SV_ThreadFunc(void *voiddata)
3940 prvm_prog_t *prog = SVVM_prog;
3941 qboolean playing = false;
3942 double sv_timer = 0;
3943 double sv_deltarealtime, sv_oldrealtime, sv_realtime;
3947 sv_realtime = Sys_DirtyTime();
3948 while (!svs.threadstop)
3950 // FIXME: we need to handle Host_Error in the server thread somehow
3951 // if (setjmp(sv_abortframe))
3952 // continue; // something bad happened in the server game
3954 sv_oldrealtime = sv_realtime;
3955 sv_realtime = Sys_DirtyTime();
3956 sv_deltarealtime = sv_realtime - sv_oldrealtime;
3957 if (sv_deltarealtime < 0 || sv_deltarealtime >= 1800) sv_deltarealtime = 0;
3959 sv_timer += sv_deltarealtime;
3961 svs.perf_acc_realtime += sv_deltarealtime;
3963 // 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)
3964 SV_LockThreadMutex();
3966 // Look for clients who have spawned
3969 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
3970 if(host_client->begun)
3971 if(host_client->netconnection)
3975 // don't accumulate time for the first 10 seconds of a match
3976 // so things can settle
3977 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;
3979 else if(svs.perf_acc_realtime > 5)
3981 svs.perf_cpuload = 1 - svs.perf_acc_sleeptime / svs.perf_acc_realtime;
3982 svs.perf_lost = svs.perf_acc_lost / svs.perf_acc_realtime;
3983 if(svs.perf_acc_offset_samples > 0)
3985 svs.perf_offset_max = svs.perf_acc_offset_max;
3986 svs.perf_offset_avg = svs.perf_acc_offset / svs.perf_acc_offset_samples;
3987 svs.perf_offset_sdev = sqrt(svs.perf_acc_offset_squared / svs.perf_acc_offset_samples - svs.perf_offset_avg * svs.perf_offset_avg);
3989 if(svs.perf_lost > 0 && developer_extra.integer)
3991 Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
3992 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;
3997 NetConn_ServerFrame();
3999 // if the accumulators haven't become positive yet, wait a while
4000 wait = sv_timer * -1000000.0;
4003 double time0, delta;
4004 SV_UnlockThreadMutex(); // don't keep mutex locked while sleeping
4005 if (host_maxwait.value <= 0)
4006 wait = min(wait, 1000000.0);
4008 wait = min(wait, host_maxwait.value * 1000.0);
4010 wait = 1; // because we cast to int
4011 time0 = Sys_DirtyTime();
4012 Sys_Sleep((int)wait);
4013 delta = Sys_DirtyTime() - time0;if (delta < 0 || delta >= 1800) delta = 0;
4014 svs.perf_acc_sleeptime += delta;
4018 if (sv.active && sv_timer > 0)
4020 // execute one server frame
4024 if (sys_ticrate.value <= 0)
4025 advancetime = min(sv_timer, 0.1); // don't step more than 100ms
4027 advancetime = sys_ticrate.value;
4031 offset = sv_timer + (Sys_DirtyTime() - sv_realtime); // LadyHavoc: FIXME: I don't understand this line
4032 ++svs.perf_acc_offset_samples;
4033 svs.perf_acc_offset += offset;
4034 svs.perf_acc_offset_squared += offset * offset;
4035 if(svs.perf_acc_offset_max < offset)
4036 svs.perf_acc_offset_max = offset;
4039 // only advance time if not paused
4040 // the game also pauses in singleplayer when menu or console is used
4041 sv.frametime = advancetime * host_timescale.value;
4042 if (host_framerate.value)
4043 sv.frametime = host_framerate.value;
4044 if (sv.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused)))
4047 sv_timer -= advancetime;
4049 // move things around and think unless paused
4053 // send all messages to the clients
4054 SV_SendClientMessages();
4056 if (sv.paused == 1 && sv_realtime > sv.pausedstart && sv.pausedstart > 0)
4058 PRVM_serverglobalfloat(time) = sv.time;
4059 prog->globals.fp[OFS_PARM0] = sv_realtime - sv.pausedstart;
4060 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_PausedTic), "QC function SV_PausedTic is missing");
4063 // send an heartbeat if enough time has passed since the last one
4064 NetConn_Heartbeat(0);
4068 // we're back to safe code now
4069 SV_UnlockThreadMutex();
4071 // if there is some time remaining from this frame, reset the timers
4074 svs.perf_acc_lost += sv_timer;
4081 void SV_StartThread(void)
4083 if (!sv_threaded.integer || !Thread_HasThreads())
4085 svs.threaded = true;
4086 svs.threadstop = false;
4087 svs.threadmutex = Thread_CreateMutex();
4088 svs.thread = Thread_CreateThread(SV_ThreadFunc, NULL);
4091 void SV_StopThread(void)
4095 svs.threadstop = true;
4096 Thread_WaitThread(svs.thread, 0);
4097 Thread_DestroyMutex(svs.threadmutex);
4098 svs.threaded = false;