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
27 static void SV_SaveEntFile_f(void);
28 static void SV_StartDownload_f(void);
29 static void SV_Download_f(void);
30 static void SV_VM_Setup();
31 extern cvar_t net_connecttimeout;
33 void VM_CustomStats_Clear (void);
34 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
36 cvar_t coop = {0, "coop","0", "coop mode, 0 = no coop, 1 = coop mode, multiple players playing through the singleplayer game (coop mode also shuts off deathmatch)"};
37 cvar_t deathmatch = {0, "deathmatch","0", "deathmatch mode, values depend on mod but typically 0 = no deathmatch, 1 = normal deathmatch with respawning weapons, 2 = weapons stay (players can only pick up new weapons)"};
38 cvar_t fraglimit = {CVAR_NOTIFY, "fraglimit","0", "ends level if this many frags is reached by any player"};
39 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
40 cvar_t noexit = {CVAR_NOTIFY, "noexit","0", "kills anyone attempting to use an exit"};
41 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
42 cvar_t pausable = {0, "pausable","1", "allow players to pause or not"};
43 cvar_t pr_checkextension = {CVAR_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"};
44 cvar_t samelevel = {CVAR_NOTIFY, "samelevel","0", "repeats same level if level ends (due to timelimit or someone hitting an exit)"};
45 cvar_t skill = {0, "skill","1", "difficulty level of game, affects monster layouts in levels, 0 = easy, 1 = normal, 2 = hard, 3 = nightmare (same layout as hard but monsters fire twice)"};
46 cvar_t slowmo = {0, "slowmo", "1.0", "controls game speed, 0.5 is half speed, 2 is double speed"};
48 cvar_t sv_accelerate = {0, "sv_accelerate", "10", "rate at which a player accelerates to sv_maxspeed"};
49 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2", "maximum cosine angle for quake's vertical autoaim, a value above 1 completely disables the autoaim, quake used 0.93"};
50 cvar_t sv_airaccel_qw = {0, "sv_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration"};
51 cvar_t sv_airaccel_sideways_friction = {0, "sv_airaccel_sideways_friction", "", "anti-sideways movement stabilization (reduces speed gain when zigzagging)"};
52 cvar_t sv_airaccelerate = {0, "sv_airaccelerate", "-1", "rate at which a player accelerates to sv_maxairspeed while in the air, if less than 0 the sv_accelerate variable is used instead"};
53 cvar_t sv_allowdownloads = {0, "sv_allowdownloads", "1", "whether to allow clients to download files from the server (does not affect http downloads)"};
54 cvar_t sv_allowdownloads_archive = {0, "sv_allowdownloads_archive", "0", "whether to allow downloads of archives (pak/pk3)"};
55 cvar_t sv_allowdownloads_config = {0, "sv_allowdownloads_config", "0", "whether to allow downloads of config files (cfg)"};
56 cvar_t sv_allowdownloads_dlcache = {0, "sv_allowdownloads_dlcache", "0", "whether to allow downloads of dlcache files (dlcache/)"};
57 cvar_t sv_allowdownloads_inarchive = {0, "sv_allowdownloads_inarchive", "0", "whether to allow downloads from archives (pak/pk3)"};
58 cvar_t sv_areagrid_mingridsize = {CVAR_NOTIFY, "sv_areagrid_mingridsize", "64", "minimum areagrid cell size, smaller values work better for lots of small objects, higher values for large objects"};
59 cvar_t sv_checkforpacketsduringsleep = {0, "sv_checkforpacketsduringsleep", "0", "uses select() function to wait between frames which can be interrupted by packets being received, instead of Sleep()/usleep()/SDL_Sleep() functions which do not check for packets"};
60 cvar_t sv_clmovement_enable = {0, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"};
61 cvar_t sv_clmovement_minping = {0, "sv_clmovement_minping", "0", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"};
62 cvar_t sv_clmovement_maxnetfps = {0, "sv_clmovement_maxnetfps", "120", "max amount of movement packets to accept per second"};
63 cvar_t sv_clmovement_minping_disabletime = {0, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"};
64 cvar_t sv_clmovement_inputtimeout = {0, "sv_clmovement_inputtimeout", "0.2", "when a client does not send input for this many seconds, force them to move anyway (unlike QuakeWorld)"};
65 cvar_t sv_cullentities_nevercullbmodels = {0, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"};
66 cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"};
67 cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
68 cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"};
69 cvar_t sv_cullentities_trace_delay = {0, "sv_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
70 cvar_t sv_cullentities_trace_delay_players = {0, "sv_cullentities_trace_delay_players", "0.2", "number of seconds until the entity gets actually culled if it is a player entity"};
71 cvar_t sv_cullentities_trace_enlarge = {0, "sv_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
72 cvar_t sv_cullentities_trace_prediction = {0, "sv_cullentities_trace_prediction", "1", "also trace from the predicted player position"};
73 cvar_t sv_cullentities_trace_samples = {0, "sv_cullentities_trace_samples", "1", "number of samples to test for entity culling"};
74 cvar_t sv_cullentities_trace_samples_extra = {0, "sv_cullentities_trace_samples_extra", "2", "number of samples to test for entity culling when the entity affects its surroundings by e.g. dlight"};
75 cvar_t sv_cullentities_trace_samples_players = {0, "sv_cullentities_trace_samples_players", "8", "number of samples to test for entity culling when the entity is a player entity"};
76 cvar_t sv_debugmove = {CVAR_NOTIFY, "sv_debugmove", "0", "disables collision detection optimizations for debugging purposes"};
77 cvar_t sv_echobprint = {CVAR_SAVE, "sv_echobprint", "1", "prints gamecode bprint() calls to server console"};
78 cvar_t sv_edgefriction = {0, "edgefriction", "1", "how much you slow down when nearing a ledge you might fall off, multiplier of sv_friction (Quake used 2, QuakeWorld used 1 due to a bug in physics code)"};
79 cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"};
80 cvar_t sv_fixedframeratesingleplayer = {0, "sv_fixedframeratesingleplayer", "1", "allows you to use server-style timing system in singleplayer (don't run faster than sys_ticrate)"};
81 cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"};
82 cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"};
83 cvar_t sv_gameplayfix_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
84 cvar_t sv_gameplayfix_delayprojectiles = {0, "sv_gameplayfix_delayprojectiles", "1", "causes entities to not move on the same frame they are spawned, meaning that projectiles wait until the next frame to perform their first move, giving proper interpolation and rocket trails, but making weapons harder to use at low framerates"};
85 cvar_t sv_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
86 cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect = {0, "sv_gameplayfix_droptofloorstartsolid_nudgetocorrect", "1", "tries to nudge stuck items and monsters out of walls before droptofloor is performed"};
87 cvar_t sv_gameplayfix_easierwaterjump = {0, "sv_gameplayfix_easierwaterjump", "1", "changes water jumping to make it easier to get out of water (exactly like in QuakeWorld)"};
88 cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"};
89 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
90 cvar_t sv_gameplayfix_multiplethinksperframe = {0, "sv_gameplayfix_multiplethinksperframe", "1", "allows entities to think more often than the server framerate, primarily useful for very high fire rate weapons"};
91 cvar_t sv_gameplayfix_slidemoveprojectiles = {0, "sv_gameplayfix_slidemoveprojectiles", "1", "allows MOVETYPE_FLY/FLYMISSILE/TOSS/BOUNCE/BOUNCEMISSILE entities to finish their move in a frame even if they hit something, fixes 'gravity accumulation' bug for grenades on steep slopes"};
92 cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
93 cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
94 cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"};
95 cvar_t sv_gameplayfix_stepwhilejumping = {0, "sv_gameplayfix_stepwhilejumping", "1", "applies step-up onto a ledge even while airborn, useful if you would otherwise just-miss the floor when running across small areas with gaps (for instance running across the moving platforms in dm2, or jumping to the megahealth and red armor in dm2 rather than using the bridge)"};
96 cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
97 cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
98 cvar_t sv_gameplayfix_gravityunaffectedbyticrate = {0, "sv_gameplayfix_gravityunaffectedbyticrate", "0", "fix some ticrate issues in physics."};
99 cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"};
100 cvar_t sv_idealpitchscale = {0, "sv_idealpitchscale","0.8", "how much to look up/down slopes and stairs when not using freelook"};
101 cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping (sv_gameplayfix_stepwhilejumping must also be 1)"};
102 cvar_t sv_jumpvelocity = {0, "sv_jumpvelocity", "270", "cvar that can be used by QuakeC code for jump velocity"};
103 cvar_t sv_maxairspeed = {0, "sv_maxairspeed", "30", "maximum speed a player can accelerate to when airborn (note that it is possible to completely stop by moving the opposite direction)"};
104 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "1000000", "upper limit on client rate cvar, should reflect your network connection quality"};
105 cvar_t sv_maxspeed = {CVAR_NOTIFY, "sv_maxspeed", "320", "maximum speed a player can accelerate to when on ground (can be exceeded by tricks)"};
106 cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000", "universal speed limit on all entities"};
107 cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "0", "enables simpler/buggier player physics (not recommended)"};
108 cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0", "prevents MOVETYPE_STEP entities (monsters) from moving"};
109 cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables QuakeC function to override player physics"};
110 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
111 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
112 cvar_t sv_random_seed = {0, "sv_random_seed", "", "random seed; when set, on every map start this random seed is used to initialize the random number generator. Don't touch it unless for benchmarking or debugging"};
113 cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
114 cvar_t sv_sound_land = {0, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"};
115 cvar_t sv_sound_watersplash = {0, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"};
116 cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"};
117 cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"};
118 cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"};
119 cvar_t sv_wateraccelerate = {0, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in the air, if less than 0 the sv_accelerate variable is used instead"};
120 cvar_t sv_waterfriction = {CVAR_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"};
121 cvar_t sys_ticrate = {CVAR_SAVE, "sys_ticrate","0.0138889", "how long a server frame is in seconds, 0.05 is 20fps server rate, 0.1 is 10fps (can not be set higher than 0.1), 0 runs as many server frames as possible (makes games against bots a little smoother, overwhelms network players), 0.0138889 matches QuakeWorld physics"};
122 cvar_t teamplay = {CVAR_NOTIFY, "teamplay","0", "teamplay mode, values depend on mod but typically 0 = no teams, 1 = no team damage no self damage, 2 = team damage and self damage, some mods support 3 = no team damage but can damage self"};
123 cvar_t timelimit = {CVAR_NOTIFY, "timelimit","0", "ends level at this time (in minutes)"};
125 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
126 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
127 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
128 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
129 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
130 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
131 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
132 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
133 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
134 cvar_t temp1 = {0, "temp1","0", "general cvar for mods to use, in stock id1 this selects which death animation to use on players (0 = random death, other values select specific death scenes)"};
136 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
137 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
138 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
139 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
140 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
141 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
142 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
143 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
144 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
145 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
146 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
147 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
148 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
149 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
150 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
151 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
152 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
153 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
154 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
155 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
156 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
158 cvar_t sv_autodemo_perclient = {CVAR_SAVE, "sv_autodemo_perclient", "0", "set to 1 to enable autorecorded per-client demos (they'll start to record at the beginning of a match); set it to 2 to also record client->server packets (for debugging)"};
159 cvar_t sv_autodemo_perclient_nameformat = {CVAR_SAVE, "sv_autodemo_perclient_nameformat", "sv_autodemos/%Y-%m-%d_%H-%M", "The format of the sv_autodemo_perclient filename, followed by the map name, the client number and the IP address + port number, separated by underscores (the date is encoded using strftime escapes)" };
161 cvar_t halflifebsp = {0, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"};
166 mempool_t *sv_mempool = NULL;
168 extern cvar_t slowmo;
169 extern float scr_centertime_off;
171 // MUST match effectnameindex_t in client.h
172 static const char *standardeffectnames[EFFECT_TOTAL] =
196 "TE_TEI_BIGEXPLOSION",
212 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
214 prvm_required_field_t reqfields[] =
216 {ev_entity, "cursor_trace_ent"},
217 {ev_entity, "drawonlytoclient"},
218 {ev_entity, "exteriormodeltoclient"},
219 {ev_entity, "nodrawtoclient"},
220 {ev_entity, "tag_entity"},
221 {ev_entity, "viewmodelforclient"},
222 {ev_float, "SendFlags"},
223 {ev_float, "Version"},
225 {ev_float, "ammo_cells1"},
226 {ev_float, "ammo_lava_nails"},
227 {ev_float, "ammo_multi_rockets"},
228 {ev_float, "ammo_nails1"},
229 {ev_float, "ammo_plasma"},
230 {ev_float, "ammo_rockets1"},
231 {ev_float, "ammo_shells1"},
232 {ev_float, "button3"},
233 {ev_float, "button4"},
234 {ev_float, "button5"},
235 {ev_float, "button6"},
236 {ev_float, "button7"},
237 {ev_float, "button8"},
238 {ev_float, "button9"},
239 {ev_float, "button10"},
240 {ev_float, "button11"},
241 {ev_float, "button12"},
242 {ev_float, "button13"},
243 {ev_float, "button14"},
244 {ev_float, "button15"},
245 {ev_float, "button16"},
246 {ev_float, "buttonchat"},
247 {ev_float, "buttonuse"},
248 {ev_float, "clientcolors"},
249 {ev_float, "cursor_active"},
250 {ev_float, "disableclientprediction"},
251 {ev_float, "fullbright"},
252 {ev_float, "glow_color"},
253 {ev_float, "glow_size"},
254 {ev_float, "glow_trail"},
255 {ev_float, "gravity"},
256 {ev_float, "idealpitch"},
257 {ev_float, "items2"},
258 {ev_float, "light_lev"},
259 {ev_float, "modelflags"},
260 {ev_float, "pflags"},
262 {ev_float, "pitch_speed"},
263 {ev_float, "pmodel"},
264 {ev_float, "renderamt"}, // HalfLife support
265 {ev_float, "rendermode"}, // HalfLife support
268 {ev_float, "tag_index"},
269 {ev_float, "viewzoom"},
270 {ev_function, "SendEntity"},
271 {ev_function, "contentstransition"}, // DRESK - Support for Entity Contents Transition Event
272 {ev_function, "customizeentityforclient"},
273 {ev_function, "movetypesteplandevent"}, // DRESK - Support for MOVETYPE_STEP Entity Land Event
274 {ev_string, "netaddress"},
275 {ev_string, "playermodel"},
276 {ev_string, "playerskin"},
277 {ev_vector, "color"},
278 {ev_vector, "colormod"},
279 {ev_vector, "cursor_screen"},
280 {ev_vector, "cursor_trace_endpos"},
281 {ev_vector, "cursor_trace_start"},
282 {ev_vector, "movement"},
283 {ev_vector, "punchvector"},
288 //============================================================================
290 void SV_AreaStats_f(void)
292 World_PrintAreaStats(&sv.world, "server");
302 // init the csqc progs cvars, since they are updated/used by the server code
303 // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
304 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
305 extern cvar_t csqc_progcrc;
306 extern cvar_t csqc_progsize;
307 Cvar_RegisterVariable (&csqc_progname);
308 Cvar_RegisterVariable (&csqc_progcrc);
309 Cvar_RegisterVariable (&csqc_progsize);
311 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
312 Cmd_AddCommand("sv_areastats", SV_AreaStats_f, "prints statistics on entity culling during collision traces");
313 Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
314 Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server");
316 Cvar_RegisterVariable (&coop);
317 Cvar_RegisterVariable (&deathmatch);
318 Cvar_RegisterVariable (&fraglimit);
319 Cvar_RegisterVariable (&gamecfg);
320 Cvar_RegisterVariable (&noexit);
321 Cvar_RegisterVariable (&nomonsters);
322 Cvar_RegisterVariable (&pausable);
323 Cvar_RegisterVariable (&pr_checkextension);
324 Cvar_RegisterVariable (&samelevel);
325 Cvar_RegisterVariable (&skill);
326 Cvar_RegisterVariable (&slowmo);
327 Cvar_RegisterVariable (&sv_accelerate);
328 Cvar_RegisterVariable (&sv_aim);
329 Cvar_RegisterVariable (&sv_airaccel_qw);
330 Cvar_RegisterVariable (&sv_airaccel_sideways_friction);
331 Cvar_RegisterVariable (&sv_airaccelerate);
332 Cvar_RegisterVariable (&sv_allowdownloads);
333 Cvar_RegisterVariable (&sv_allowdownloads_archive);
334 Cvar_RegisterVariable (&sv_allowdownloads_config);
335 Cvar_RegisterVariable (&sv_allowdownloads_dlcache);
336 Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
337 Cvar_RegisterVariable (&sv_areagrid_mingridsize);
338 Cvar_RegisterVariable (&sv_checkforpacketsduringsleep);
339 Cvar_RegisterVariable (&sv_clmovement_enable);
340 Cvar_RegisterVariable (&sv_clmovement_maxnetfps);
341 Cvar_RegisterVariable (&sv_clmovement_minping);
342 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
343 Cvar_RegisterVariable (&sv_clmovement_inputtimeout);
344 Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels);
345 Cvar_RegisterVariable (&sv_cullentities_pvs);
346 Cvar_RegisterVariable (&sv_cullentities_stats);
347 Cvar_RegisterVariable (&sv_cullentities_trace);
348 Cvar_RegisterVariable (&sv_cullentities_trace_delay);
349 Cvar_RegisterVariable (&sv_cullentities_trace_delay_players);
350 Cvar_RegisterVariable (&sv_cullentities_trace_enlarge);
351 Cvar_RegisterVariable (&sv_cullentities_trace_prediction);
352 Cvar_RegisterVariable (&sv_cullentities_trace_samples);
353 Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra);
354 Cvar_RegisterVariable (&sv_cullentities_trace_samples_players);
355 Cvar_RegisterVariable (&sv_debugmove);
356 Cvar_RegisterVariable (&sv_echobprint);
357 Cvar_RegisterVariable (&sv_edgefriction);
358 Cvar_RegisterVariable (&sv_entpatch);
359 Cvar_RegisterVariable (&sv_fixedframeratesingleplayer);
360 Cvar_RegisterVariable (&sv_freezenonclients);
361 Cvar_RegisterVariable (&sv_friction);
362 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
363 Cvar_RegisterVariable (&sv_gameplayfix_delayprojectiles);
364 Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
365 Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid_nudgetocorrect);
366 Cvar_RegisterVariable (&sv_gameplayfix_easierwaterjump);
367 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
368 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
369 Cvar_RegisterVariable (&sv_gameplayfix_multiplethinksperframe);
370 Cvar_RegisterVariable (&sv_gameplayfix_slidemoveprojectiles);
371 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
372 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
373 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
374 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
375 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
376 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
377 Cvar_RegisterVariable (&sv_gameplayfix_gravityunaffectedbyticrate);
378 Cvar_RegisterVariable (&sv_gravity);
379 Cvar_RegisterVariable (&sv_idealpitchscale);
380 Cvar_RegisterVariable (&sv_jumpstep);
381 Cvar_RegisterVariable (&sv_jumpvelocity);
382 Cvar_RegisterVariable (&sv_maxairspeed);
383 Cvar_RegisterVariable (&sv_maxrate);
384 Cvar_RegisterVariable (&sv_maxspeed);
385 Cvar_RegisterVariable (&sv_maxvelocity);
386 Cvar_RegisterVariable (&sv_newflymove);
387 Cvar_RegisterVariable (&sv_nostep);
388 Cvar_RegisterVariable (&sv_playerphysicsqc);
389 Cvar_RegisterVariable (&sv_progs);
390 Cvar_RegisterVariable (&sv_protocolname);
391 Cvar_RegisterVariable (&sv_random_seed);
392 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
393 Cvar_RegisterVariable (&sv_sound_land);
394 Cvar_RegisterVariable (&sv_sound_watersplash);
395 Cvar_RegisterVariable (&sv_stepheight);
396 Cvar_RegisterVariable (&sv_stopspeed);
397 Cvar_RegisterVariable (&sv_wallfriction);
398 Cvar_RegisterVariable (&sv_wateraccelerate);
399 Cvar_RegisterVariable (&sv_waterfriction);
400 Cvar_RegisterVariable (&sys_ticrate);
401 Cvar_RegisterVariable (&teamplay);
402 Cvar_RegisterVariable (&timelimit);
404 Cvar_RegisterVariable (&saved1);
405 Cvar_RegisterVariable (&saved2);
406 Cvar_RegisterVariable (&saved3);
407 Cvar_RegisterVariable (&saved4);
408 Cvar_RegisterVariable (&savedgamecfg);
409 Cvar_RegisterVariable (&scratch1);
410 Cvar_RegisterVariable (&scratch2);
411 Cvar_RegisterVariable (&scratch3);
412 Cvar_RegisterVariable (&scratch4);
413 Cvar_RegisterVariable (&temp1);
415 // LordHavoc: Nehahra uses these to pass data around cutscene demos
416 if (gamemode == GAME_NEHAHRA)
418 Cvar_RegisterVariable (&nehx00);
419 Cvar_RegisterVariable (&nehx01);
420 Cvar_RegisterVariable (&nehx02);
421 Cvar_RegisterVariable (&nehx03);
422 Cvar_RegisterVariable (&nehx04);
423 Cvar_RegisterVariable (&nehx05);
424 Cvar_RegisterVariable (&nehx06);
425 Cvar_RegisterVariable (&nehx07);
426 Cvar_RegisterVariable (&nehx08);
427 Cvar_RegisterVariable (&nehx09);
428 Cvar_RegisterVariable (&nehx10);
429 Cvar_RegisterVariable (&nehx11);
430 Cvar_RegisterVariable (&nehx12);
431 Cvar_RegisterVariable (&nehx13);
432 Cvar_RegisterVariable (&nehx14);
433 Cvar_RegisterVariable (&nehx15);
434 Cvar_RegisterVariable (&nehx16);
435 Cvar_RegisterVariable (&nehx17);
436 Cvar_RegisterVariable (&nehx18);
437 Cvar_RegisterVariable (&nehx19);
439 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
441 Cvar_RegisterVariable (&sv_autodemo_perclient);
442 Cvar_RegisterVariable (&sv_autodemo_perclient_nameformat);
444 Cvar_RegisterVariable (&halflifebsp);
446 // any special defaults for gamemodes go here
447 if (gamemode == GAME_HIPNOTIC)
449 // hipnotic mission pack has issues in their 'friendly monster' ai, which seem to attempt to attack themselves for some reason when findradius() returns non-solid entities.
450 Cvar_SetValueQuick (&sv_gameplayfix_blowupfallenzombies, 0);
451 // hipnotic mission pack has issues with bobbing water entities 'jittering' between different heights on alternate frames at the default 0.0138889 ticrate, 0.02 avoids this issue
452 Cvar_SetValueQuick (&sys_ticrate, 0.02);
454 if (gamemode == GAME_ROGUE)
456 // rogue mission pack has a guardian boss that does not wake up if findradius returns one of the entities around its spawn area
457 Cvar_SetValueQuick (&sv_gameplayfix_findradiusdistancetobox, 0);
460 sv_mempool = Mem_AllocPool("server", 0, NULL);
463 static void SV_SaveEntFile_f(void)
465 char basename[MAX_QPATH];
466 if (!sv.active || !sv.worldmodel)
468 Con_Print("Not running a server\n");
471 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
472 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
477 =============================================================================
481 =============================================================================
488 Make sure the event gets sent to all clients
491 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
495 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
497 MSG_WriteByte (&sv.datagram, svc_particle);
498 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
499 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
500 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
501 for (i=0 ; i<3 ; i++)
502 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
503 MSG_WriteByte (&sv.datagram, count);
504 MSG_WriteByte (&sv.datagram, color);
505 SV_FlushBroadcastMessages();
512 Make sure the event gets sent to all clients
515 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
517 if (modelindex >= 256 || startframe >= 256)
519 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
521 MSG_WriteByte (&sv.datagram, svc_effect2);
522 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
523 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
524 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
525 MSG_WriteShort (&sv.datagram, modelindex);
526 MSG_WriteShort (&sv.datagram, startframe);
527 MSG_WriteByte (&sv.datagram, framecount);
528 MSG_WriteByte (&sv.datagram, framerate);
532 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
534 MSG_WriteByte (&sv.datagram, svc_effect);
535 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
536 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
537 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
538 MSG_WriteByte (&sv.datagram, modelindex);
539 MSG_WriteByte (&sv.datagram, startframe);
540 MSG_WriteByte (&sv.datagram, framecount);
541 MSG_WriteByte (&sv.datagram, framerate);
543 SV_FlushBroadcastMessages();
550 Each entity can have eight independant sound sources, like voice,
553 Channel 0 is an auto-allocate channel, the others override anything
554 already running on that entity/channel pair.
556 An attenuation of 0 will play full volume everywhere in the level.
557 Larger attenuations will drop off. (max 4 attenuation)
561 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
563 int sound_num, field_mask, i, ent;
565 if (volume < 0 || volume > 255)
567 Con_Printf ("SV_StartSound: volume = %i\n", volume);
571 if (attenuation < 0 || attenuation > 4)
573 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
577 if (channel < 0 || channel > 7)
579 Con_Printf ("SV_StartSound: channel = %i\n", channel);
583 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
586 // find precache number for sound
587 sound_num = SV_SoundIndex(sample, 1);
591 ent = PRVM_NUM_FOR_EDICT(entity);
594 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
595 field_mask |= SND_VOLUME;
596 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
597 field_mask |= SND_ATTENUATION;
599 field_mask |= SND_LARGEENTITY;
600 if (sound_num >= 256 || channel >= 8)
601 field_mask |= SND_LARGESOUND;
603 // directed messages go only to the entity they are targeted on
604 MSG_WriteByte (&sv.datagram, svc_sound);
605 MSG_WriteByte (&sv.datagram, field_mask);
606 if (field_mask & SND_VOLUME)
607 MSG_WriteByte (&sv.datagram, volume);
608 if (field_mask & SND_ATTENUATION)
609 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
610 if (field_mask & SND_LARGEENTITY)
612 MSG_WriteShort (&sv.datagram, ent);
613 MSG_WriteByte (&sv.datagram, channel);
616 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
617 if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_NEHAHRABJP2)
618 MSG_WriteShort (&sv.datagram, sound_num);
620 MSG_WriteByte (&sv.datagram, sound_num);
621 for (i = 0;i < 3;i++)
622 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
623 SV_FlushBroadcastMessages();
630 Nearly the same logic as SV_StartSound, except an origin
631 instead of an entity is provided and channel is omitted.
633 The entity sent to the client is 0 (world) and the channel
634 is 0 (CHAN_AUTO). SND_LARGEENTITY will never occur in this
635 function, therefore the check for it is omitted.
639 void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation)
641 int sound_num, field_mask, i;
643 if (volume < 0 || volume > 255)
645 Con_Printf ("SV_StartPointSound: volume = %i\n", volume);
649 if (attenuation < 0 || attenuation > 4)
651 Con_Printf ("SV_StartPointSound: attenuation = %f\n", attenuation);
655 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
658 // find precache number for sound
659 sound_num = SV_SoundIndex(sample, 1);
664 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
665 field_mask |= SND_VOLUME;
666 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
667 field_mask |= SND_ATTENUATION;
668 if (sound_num >= 256)
669 field_mask |= SND_LARGESOUND;
671 // directed messages go only to the entity they are targeted on
672 MSG_WriteByte (&sv.datagram, svc_sound);
673 MSG_WriteByte (&sv.datagram, field_mask);
674 if (field_mask & SND_VOLUME)
675 MSG_WriteByte (&sv.datagram, volume);
676 if (field_mask & SND_ATTENUATION)
677 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
678 // Always write entnum 0 for the world entity
679 MSG_WriteShort (&sv.datagram, (0<<3) | 0);
680 if (field_mask & SND_LARGESOUND)
681 MSG_WriteShort (&sv.datagram, sound_num);
683 MSG_WriteByte (&sv.datagram, sound_num);
684 for (i = 0;i < 3;i++)
685 MSG_WriteCoord (&sv.datagram, origin[i], sv.protocol);
686 SV_FlushBroadcastMessages();
690 ==============================================================================
694 ==============================================================================
701 Sends the first message from the server to a connected client.
702 This will be sent on the initial connection and upon each server load.
705 void SV_SendServerinfo (client_t *client)
710 // we know that this client has a netconnection and thus is not a bot
712 // edicts get reallocated on level changes, so we need to update it here
713 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
715 // clear cached stuff that depends on the level
716 client->weaponmodel[0] = 0;
717 client->weaponmodelindex = 0;
719 // LordHavoc: clear entityframe tracking
720 client->latestframenum = 0;
722 // initialize the movetime, so a speedhack can't make use of the time before this client joined
723 client->cmd.time = sv.time;
725 if (client->entitydatabase)
726 EntityFrame_FreeDatabase(client->entitydatabase);
727 if (client->entitydatabase4)
728 EntityFrame4_FreeDatabase(client->entitydatabase4);
729 if (client->entitydatabase5)
730 EntityFrame5_FreeDatabase(client->entitydatabase5);
732 memset(client->stats, 0, sizeof(client->stats));
733 memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits));
735 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)
737 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
738 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
739 else if (sv.protocol == PROTOCOL_DARKPLACES4)
740 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
742 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
745 // reset csqc entity versions
746 for (i = 0;i < prog->max_edicts;i++)
748 client->csqcentityscope[i] = 0;
749 client->csqcentitysendflags[i] = 0xFFFFFF;
750 client->csqcentityglobalhistory[i] = 0;
752 for (i = 0;i < NUM_CSQCENTITYDB_FRAMES;i++)
754 client->csqcentityframehistory[i].num = 0;
755 client->csqcentityframehistory[i].framenum = -1;
757 client->csqcnumedicts = 0;
758 client->csqcentityframehistory_next = 0;
760 SZ_Clear (&client->netconnection->message);
761 MSG_WriteByte (&client->netconnection->message, svc_print);
762 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
763 MSG_WriteString (&client->netconnection->message,message);
765 SV_StopDemoRecording(client); // to split up demos into different files
766 if(sv_autodemo_perclient.integer && client->netconnection)
768 char demofile[MAX_OSPATH];
769 char levelname[MAX_QPATH];
770 char ipaddress[MAX_QPATH];
773 // start a new demo file
774 strlcpy(levelname, FS_FileWithoutPath(sv.worldmodel->name), sizeof(levelname));
775 if (strrchr(levelname, '.'))
776 *(strrchr(levelname, '.')) = 0;
778 LHNETADDRESS_ToString(&(client->netconnection->peeraddress), ipaddress, sizeof(ipaddress), true);
779 for(i = 0; ipaddress[i]; ++i)
780 if(!isalnum(ipaddress[i]))
782 dpsnprintf (demofile, sizeof(demofile), "%s_%s_%d_%s.dem", Sys_TimeString (sv_autodemo_perclient_nameformat.string), levelname, PRVM_NUM_FOR_EDICT(client->edict), ipaddress);
784 SV_StartDemoRecording(client, demofile, -1);
787 //[515]: init csprogs according to version of svprogs, check the crc, etc.
788 if (sv.csqc_progname[0])
791 Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
792 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
793 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
794 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
795 MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize));
796 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
797 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
799 if(client->sv_demo_file != NULL)
802 char buf[NET_MAXMESSAGE];
805 sb.data = (unsigned char *) buf;
806 sb.maxsize = sizeof(buf);
808 while(MakeDownloadPacket(sv.csqc_progname, svs.csqc_progdata, sv.csqc_progsize, sv.csqc_progcrc, i++, &sb, sv.protocol))
809 SV_WriteDemoMessage(client, &sb, false);
812 //[515]: init stufftext string (it is sent before svc_serverinfo)
813 val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
816 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
817 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
821 //if (sv_allowdownloads.integer)
822 // always send the info that the server supports the protocol, even if downloads are forbidden
823 // only because of that, the CSQC exception can work
825 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
826 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 2\n");
829 // send at this time so it's guaranteed to get executed at the right time
833 host_client = client;
834 Curl_SendRequirements();
838 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
839 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
840 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
842 if (!coop.integer && deathmatch.integer)
843 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
845 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
847 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
849 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
850 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
851 MSG_WriteByte (&client->netconnection->message, 0);
853 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
854 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
855 MSG_WriteByte (&client->netconnection->message, 0);
858 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
859 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
860 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
863 // store this in clientcamera, too
864 client->clientcamera = PRVM_NUM_FOR_EDICT(client->edict);
865 MSG_WriteByte (&client->netconnection->message, svc_setview);
866 MSG_WriteShort (&client->netconnection->message, client->clientcamera);
868 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
869 MSG_WriteByte (&client->netconnection->message, 1);
871 client->spawned = false; // need prespawn, spawn, etc
872 client->sendsignon = 1; // send this message, and increment to 2, 2 will be set to 0 by the prespawn command
874 // clear movement info until client enters the new level properly
875 memset(&client->cmd, 0, sizeof(client->cmd));
876 client->movesequence = 0;
877 #ifdef NUM_PING_TIMES
878 for (i = 0;i < NUM_PING_TIMES;i++)
879 client->ping_times[i] = 0;
880 client->num_pings = 0;
884 // allow the client some time to send his keepalives, even if map loading took ages
885 client->netconnection->timeout = realtime + net_connecttimeout.value;
892 Initializes a client_t for a new net connection. This will only be called
893 once for a player each game, not once for each level change.
896 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
900 float spawn_parms[NUM_SPAWN_PARMS];
902 client = svs.clients + clientnum;
904 // set up the client_t
906 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
907 memset (client, 0, sizeof(*client));
908 client->active = true;
909 client->netconnection = netconnection;
911 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
913 strlcpy(client->name, "unconnected", sizeof(client->name));
914 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
915 client->spawned = false;
916 client->edict = PRVM_EDICT_NUM(clientnum+1);
917 if (client->netconnection)
918 client->netconnection->message.allowoverflow = true; // we can catch it
919 // prepare the unreliable message buffer
920 client->unreliablemsg.data = client->unreliablemsg_data;
921 client->unreliablemsg.maxsize = sizeof(client->unreliablemsg_data);
922 // updated by receiving "rate" command from client, this is also the default if not using a DP client
923 client->rate = 1000000000;
924 // no limits for local player
925 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
926 client->rate = 1000000000;
927 client->connecttime = realtime;
930 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
933 // call the progs to get default spawn parms for the new client
934 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
935 prog->globals.server->self = 0;
936 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
937 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
938 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
940 // set up the entity for this client (including .colormap, .team, etc)
941 PRVM_ED_ClearEdict(client->edict);
944 // don't call SendServerinfo for a fresh botclient because its fields have
945 // not been set up by the qc yet
946 if (client->netconnection)
947 SV_SendServerinfo (client);
949 client->spawned = true;
954 ===============================================================================
958 ===============================================================================
962 =============================================================================
964 The PVS must include a small area around the client to allow head bobbing
965 or other small motion on the client side. Otherwise, a bob might cause an
966 entity that should be visible to not show up, especially when the bob
969 =============================================================================
972 static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int enumber)
975 unsigned int sendflags;
976 unsigned int version;
977 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
978 unsigned int customizeentityforclient;
980 vec3_t cullmins, cullmaxs;
982 prvm_eval_t *val, *val2;
984 // this 2 billion unit check is actually to detect NAN origins
985 // (we really don't want to send those)
986 if (!(VectorLength2(ent->fields.server->origin) < 2000000000.0*2000000000.0))
989 // EF_NODRAW prevents sending for any reason except for your own
990 // client, so we must keep all clients in this superset
991 effects = (unsigned)ent->fields.server->effects;
993 // we can omit invisible entities with no effects that are not clients
994 // LordHavoc: this could kill tags attached to an invisible entity, I
995 // just hope we never have to support that case
996 i = (int)ent->fields.server->modelindex;
997 modelindex = (i >= 1 && i < MAX_MODELS && ent->fields.server->model && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
1000 i = (int)(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_size)->_float * 0.25f);
1001 glowsize = (unsigned char)bound(0, i, 255);
1002 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float)
1003 flags |= RENDER_GLOWTRAIL;
1004 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict)
1005 flags |= RENDER_VIEWMODEL;
1007 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[0]*256;
1008 light[0] = (unsigned short)bound(0, f, 65535);
1009 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[1]*256;
1010 light[1] = (unsigned short)bound(0, f, 65535);
1011 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[2]*256;
1012 light[2] = (unsigned short)bound(0, f, 65535);
1013 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.light_lev)->_float;
1014 light[3] = (unsigned short)bound(0, f, 65535);
1015 lightstyle = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.style)->_float;
1016 lightpflags = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float;
1018 if (gamemode == GAME_TENEBRAE)
1020 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
1024 lightpflags |= PFLAGS_FULLDYNAMIC;
1026 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
1030 light[0] = (int)(0.2*256);
1031 light[1] = (int)(1.0*256);
1032 light[2] = (int)(0.2*256);
1034 lightpflags |= PFLAGS_FULLDYNAMIC;
1038 specialvisibilityradius = 0;
1039 if (lightpflags & PFLAGS_FULLDYNAMIC)
1040 specialvisibilityradius = max(specialvisibilityradius, light[3]);
1042 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
1043 if (flags & RENDER_GLOWTRAIL)
1044 specialvisibilityradius = max(specialvisibilityradius, 100);
1045 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
1047 if (effects & EF_BRIGHTFIELD)
1048 specialvisibilityradius = max(specialvisibilityradius, 80);
1049 if (effects & EF_MUZZLEFLASH)
1050 specialvisibilityradius = max(specialvisibilityradius, 100);
1051 if (effects & EF_BRIGHTLIGHT)
1052 specialvisibilityradius = max(specialvisibilityradius, 400);
1053 if (effects & EF_DIMLIGHT)
1054 specialvisibilityradius = max(specialvisibilityradius, 200);
1055 if (effects & EF_RED)
1056 specialvisibilityradius = max(specialvisibilityradius, 200);
1057 if (effects & EF_BLUE)
1058 specialvisibilityradius = max(specialvisibilityradius, 200);
1059 if (effects & EF_FLAME)
1060 specialvisibilityradius = max(specialvisibilityradius, 250);
1061 if (effects & EF_STARDUST)
1062 specialvisibilityradius = max(specialvisibilityradius, 100);
1065 // early culling checks
1066 // (final culling is done by SV_MarkWriteEntityStateToClient)
1067 customizeentityforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function;
1068 if (!customizeentityforclient && enumber > svs.maxclients && (!modelindex && !specialvisibilityradius))
1073 cs->number = enumber;
1074 VectorCopy(ent->fields.server->origin, cs->origin);
1075 VectorCopy(ent->fields.server->angles, cs->angles);
1077 cs->effects = effects;
1078 cs->colormap = (unsigned)ent->fields.server->colormap;
1079 cs->modelindex = modelindex;
1080 cs->skin = (unsigned)ent->fields.server->skin;
1081 cs->frame = (unsigned)ent->fields.server->frame;
1082 cs->viewmodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict;
1083 cs->exteriormodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict;
1084 cs->nodrawtoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict;
1085 cs->drawonlytoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict;
1086 cs->customizeentityforclient = customizeentityforclient;
1087 cs->tagentity = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)->edict;
1088 cs->tagindex = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
1089 cs->glowsize = glowsize;
1091 // don't need to init cs->colormod because the defaultstate did that for us
1092 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
1093 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod);
1094 if (val->vector[0] || val->vector[1] || val->vector[2])
1096 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
1097 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
1098 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
1101 cs->modelindex = modelindex;
1104 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f);
1108 cs->alpha = (unsigned char)bound(0, i, 255);
1111 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
1115 cs->alpha = (unsigned char)bound(0, i, 255);
1119 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f);
1123 cs->scale = (unsigned char)bound(0, i, 255);
1126 cs->glowcolor = 254;
1127 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
1129 cs->glowcolor = (int)f;
1131 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
1132 cs->effects |= EF_FULLBRIGHT;
1134 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.modelflags);
1135 if (val && val->_float)
1136 cs->effects |= ((unsigned int)val->_float & 0xff) << 24;
1138 if (ent->fields.server->movetype == MOVETYPE_STEP)
1139 cs->flags |= RENDER_STEP;
1140 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)
1141 cs->flags |= RENDER_LOWPRECISION;
1142 if (ent->fields.server->colormap >= 1024)
1143 cs->flags |= RENDER_COLORMAPPED;
1144 if (cs->viewmodelforclient)
1145 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
1147 cs->light[0] = light[0];
1148 cs->light[1] = light[1];
1149 cs->light[2] = light[2];
1150 cs->light[3] = light[3];
1151 cs->lightstyle = lightstyle;
1152 cs->lightpflags = lightpflags;
1154 cs->specialvisibilityradius = specialvisibilityradius;
1156 // calculate the visible box of this entity (don't use the physics box
1157 // as that is often smaller than a model, and would not count
1158 // specialvisibilityradius)
1159 if ((model = sv.models[modelindex]) && (model->type != mod_null))
1161 float scale = cs->scale * (1.0f / 16.0f);
1162 if (cs->angles[0] || cs->angles[2]) // pitch and roll
1164 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
1165 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
1167 else if (cs->angles[1])
1169 VectorMA(cs->origin, scale, model->yawmins, cullmins);
1170 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
1174 VectorMA(cs->origin, scale, model->normalmins, cullmins);
1175 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
1180 // if there is no model (or it could not be loaded), use the physics box
1181 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
1182 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
1184 if (specialvisibilityradius)
1186 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
1187 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
1188 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
1189 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
1190 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
1191 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
1194 // calculate center of bbox for network prioritization purposes
1195 VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
1197 // if culling box has moved, update pvs cluster links
1198 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
1200 VectorCopy(cullmins, ent->priv.server->cullmins);
1201 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
1202 // a value of -1 for pvs_numclusters indicates that the links are not
1203 // cached, and should be re-tested each time, this is the case if the
1204 // culling box touches too many pvs clusters to store, or if the world
1205 // model does not support FindBoxClusters
1206 ent->priv.server->pvs_numclusters = -1;
1207 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
1209 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
1210 if (i <= MAX_ENTITYCLUSTERS)
1211 ent->priv.server->pvs_numclusters = i;
1215 // we need to do some csqc entity upkeep here
1216 // get self.SendFlags and clear them
1217 // (to let the QC know that they've been read)
1218 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.SendEntity);
1221 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.SendFlags);
1222 sendflags = (unsigned int)val->_float;
1224 // legacy self.Version system
1225 val2 = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.Version);
1228 version = (unsigned int)val2->_float;
1229 if (sv.csqcentityversion[enumber] != version)
1230 sendflags = 0xFFFFFF;
1231 sv.csqcentityversion[enumber] = version;
1233 // move sendflags into the per-client sendflags
1235 for (i = 0;i < svs.maxclients;i++)
1236 svs.clients[i].csqcentitysendflags[enumber] |= sendflags;
1242 void SV_PrepareEntitiesForSending(void)
1246 // send all entities that touch the pvs
1247 sv.numsendentities = 0;
1248 sv.sendentitiesindex[0] = NULL;
1249 memset(sv.sendentitiesindex, 0, prog->num_edicts * sizeof(*sv.sendentitiesindex));
1250 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
1252 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sv.sendentities + sv.numsendentities, e))
1254 sv.sendentitiesindex[e] = sv.sendentities + sv.numsendentities;
1255 sv.numsendentities++;
1260 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
1265 if (sv.sententitiesconsideration[s->number] == sv.sententitiesmark)
1267 sv.sententitiesconsideration[s->number] = sv.sententitiesmark;
1268 sv.writeentitiestoclient_stats_totalentities++;
1270 if (s->customizeentityforclient)
1272 prog->globals.server->self = s->number;
1273 prog->globals.server->other = sv.writeentitiestoclient_cliententitynumber;
1274 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
1275 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
1279 // never reject player
1280 if (s->number != sv.writeentitiestoclient_cliententitynumber)
1282 // check various rejection conditions
1283 if (s->nodrawtoclient == sv.writeentitiestoclient_cliententitynumber)
1285 if (s->drawonlytoclient && s->drawonlytoclient != sv.writeentitiestoclient_cliententitynumber)
1287 if (s->effects & EF_NODRAW)
1289 // LordHavoc: only send entities with a model or important effects
1290 if (!s->modelindex && s->specialvisibilityradius == 0)
1293 isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*';
1294 // viewmodels don't have visibility checking
1295 if (s->viewmodelforclient)
1297 if (s->viewmodelforclient != sv.writeentitiestoclient_cliententitynumber)
1300 else if (s->tagentity)
1302 // tag attached entities simply check their parent
1303 if (!sv.sendentitiesindex[s->tagentity])
1305 SV_MarkWriteEntityStateToClient(sv.sendentitiesindex[s->tagentity]);
1306 if (sv.sententities[s->tagentity] != sv.sententitiesmark)
1309 // always send world submodels in newer protocols because they don't
1310 // generate much traffic (in old protocols they hog bandwidth)
1311 // but only if sv_cullentities_nevercullbmodels is off
1312 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
1314 // entity has survived every check so far, check if visible
1315 ed = PRVM_EDICT_NUM(s->number);
1317 // if not touching a visible leaf
1318 if (sv_cullentities_pvs.integer && sv.writeentitiestoclient_pvsbytes)
1320 if (ed->priv.server->pvs_numclusters < 0)
1322 // entity too big for clusters list
1323 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv.writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
1325 sv.writeentitiestoclient_stats_culled_pvs++;
1332 // check cached clusters list
1333 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
1334 if (CHECKPVSBIT(sv.writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
1336 if (i == ed->priv.server->pvs_numclusters)
1338 sv.writeentitiestoclient_stats_culled_pvs++;
1344 // or not seen by random tracelines
1345 if (sv_cullentities_trace.integer && !isbmodel && sv.worldmodel->brush.TraceLineOfSight)
1348 s->number <= svs.maxclients
1349 ? sv_cullentities_trace_samples_players.integer
1351 s->specialvisibilityradius
1352 ? sv_cullentities_trace_samples_extra.integer
1353 : sv_cullentities_trace_samples.integer;
1354 float enlarge = sv_cullentities_trace_enlarge.value;
1356 qboolean visible = TRUE;
1362 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv.writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
1363 break; // directly visible from the server's view
1365 if(sv_cullentities_trace_prediction.integer)
1369 // get player velocity
1370 float predtime = bound(0, host_client->ping, 0.2); // / 2
1371 // sorry, no wallhacking by high ping please, and at 200ms
1372 // ping a FPS is annoying to play anyway and a player is
1373 // likely to have changed his direction
1374 VectorMA(sv.writeentitiestoclient_testeye, predtime, host_client->edict->fields.server->velocity, predeye);
1375 if(sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv.writeentitiestoclient_testeye, predeye)) // must be able to go there...
1377 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
1378 break; // directly visible from the predicted view
1382 //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
1386 // when we get here, we can't see the entity
1392 svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number] =
1394 s->number <= svs.maxclients
1395 ? sv_cullentities_trace_delay_players.value
1396 : sv_cullentities_trace_delay.value
1398 else if (realtime > svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number])
1400 sv.writeentitiestoclient_stats_culled_trace++;
1408 // this just marks it for sending
1409 // FIXME: it would be more efficient to send here, but the entity
1410 // compressor isn't that flexible
1411 sv.writeentitiestoclient_stats_visibleentities++;
1412 sv.sententities[s->number] = sv.sententitiesmark;
1415 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int maxsize)
1417 qboolean need_empty = false;
1418 int i, numsendstates;
1420 prvm_edict_t *camera;
1422 // if there isn't enough space to accomplish anything, skip it
1423 if (msg->cursize + 25 > maxsize)
1426 sv.writeentitiestoclient_msg = msg;
1427 sv.writeentitiestoclient_clientnumber = client - svs.clients;
1429 sv.writeentitiestoclient_stats_culled_pvs = 0;
1430 sv.writeentitiestoclient_stats_culled_trace = 0;
1431 sv.writeentitiestoclient_stats_visibleentities = 0;
1432 sv.writeentitiestoclient_stats_totalentities = 0;
1434 // find the client's PVS
1435 // the real place being tested from
1436 camera = PRVM_EDICT_NUM( client->clientcamera );
1437 VectorAdd(camera->fields.server->origin, clent->fields.server->view_ofs, sv.writeentitiestoclient_testeye);
1438 sv.writeentitiestoclient_pvsbytes = 0;
1439 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
1440 sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv.writeentitiestoclient_testeye, 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs), false);
1442 sv.writeentitiestoclient_cliententitynumber = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
1444 sv.sententitiesmark++;
1446 for (i = 0;i < sv.numsendentities;i++)
1447 SV_MarkWriteEntityStateToClient(sv.sendentities + i);
1450 for (i = 0;i < sv.numsendentities;i++)
1452 if (sv.sententities[sv.sendentities[i].number] == sv.sententitiesmark)
1454 s = &sv.writeentitiestoclient_sendstates[numsendstates++];
1455 *s = sv.sendentities[i];
1456 if (s->exteriormodelforclient && s->exteriormodelforclient == sv.writeentitiestoclient_cliententitynumber)
1457 s->flags |= RENDER_EXTERIORMODEL;
1461 if (sv_cullentities_stats.integer)
1462 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);
1464 if(client->entitydatabase5)
1465 need_empty = EntityFrameCSQC_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates, client->entitydatabase5->latestframenum + 1);
1467 EntityFrameCSQC_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates, 0);
1469 if (client->entitydatabase5)
1470 EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence, need_empty);
1471 else if (client->entitydatabase4)
1473 EntityFrame4_WriteFrame(msg, maxsize, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates);
1474 Protocol_WriteStatsReliable();
1476 else if (client->entitydatabase)
1478 EntityFrame_WriteFrame(msg, maxsize, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1);
1479 Protocol_WriteStatsReliable();
1483 EntityFrameQuake_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates);
1484 Protocol_WriteStatsReliable();
1494 static void SV_CleanupEnts (void)
1499 ent = PRVM_NEXT_EDICT(prog->edicts);
1500 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1501 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1506 SV_WriteClientdataToMessage
1510 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1514 prvm_edict_t *other;
1520 float *statsf = (float *)stats;
1523 // send a damage message
1525 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1527 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1528 MSG_WriteByte (msg, svc_damage);
1529 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1530 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1531 for (i=0 ; i<3 ; i++)
1532 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1534 ent->fields.server->dmg_take = 0;
1535 ent->fields.server->dmg_save = 0;
1539 // send the current viewpos offset from the view entity
1541 SV_SetIdealPitch (); // how much to look up / down ideally
1543 // a fixangle might get lost in a dropped packet. Oh well.
1544 if(ent->fields.server->fixangle)
1546 // angle fixing was requested by global thinking code...
1547 // so store the current angles for later use
1548 memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
1549 host_client->fixangle_angles_set = TRUE;
1551 // and clear fixangle for the next frame
1552 ent->fields.server->fixangle = 0;
1555 if (host_client->fixangle_angles_set)
1557 MSG_WriteByte (msg, svc_setangle);
1558 for (i=0 ; i < 3 ; i++)
1559 MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
1560 host_client->fixangle_angles_set = FALSE;
1563 // stuff the sigil bits into the high bits of items for sbar, or else
1565 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1566 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1567 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1569 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1571 VectorClear(punchvector);
1572 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1573 VectorCopy(val->vector, punchvector);
1575 // cache weapon model name and index in client struct to save time
1576 // (this search can be almost 1% of cpu time!)
1577 s = PRVM_GetString(ent->fields.server->weaponmodel);
1578 if (strcmp(s, client->weaponmodel))
1580 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1581 client->weaponmodelindex = SV_ModelIndex(s, 1);
1585 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1586 viewzoom = (int)(val->_float * 255.0f);
1592 if ((int)ent->fields.server->flags & FL_ONGROUND)
1593 bits |= SU_ONGROUND;
1594 if (ent->fields.server->waterlevel >= 2)
1596 if (ent->fields.server->idealpitch)
1597 bits |= SU_IDEALPITCH;
1599 for (i=0 ; i<3 ; i++)
1601 if (ent->fields.server->punchangle[i])
1602 bits |= (SU_PUNCH1<<i);
1603 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)
1605 bits |= (SU_PUNCHVEC1<<i);
1606 if (ent->fields.server->velocity[i])
1607 bits |= (SU_VELOCITY1<<i);
1610 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1611 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1612 stats[STAT_ITEMS] = items;
1613 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1614 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1615 stats[STAT_WEAPON] = client->weaponmodelindex;
1616 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1617 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1618 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1619 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1620 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1621 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1622 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1623 stats[STAT_VIEWZOOM] = viewzoom;
1624 stats[STAT_TOTALSECRETS] = (int)prog->globals.server->total_secrets;
1625 stats[STAT_TOTALMONSTERS] = (int)prog->globals.server->total_monsters;
1626 // the QC bumps these itself by sending svc_'s, so we have to keep them
1627 // zero or they'll be corrected by the engine
1628 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1629 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1631 // movement settings for prediction
1632 // note: these are not sent in protocols with lower MAX_CL_STATS limits
1633 statsf[STAT_MOVEVARS_TICRATE] = sys_ticrate.value;
1634 statsf[STAT_MOVEVARS_TIMESCALE] = slowmo.value;
1635 statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
1636 statsf[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
1637 statsf[STAT_MOVEVARS_MAXSPEED] = sv_maxspeed.value;
1638 statsf[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_maxspeed.value; // FIXME: QW has a separate cvar for this
1639 statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
1640 statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value >= 0 ? sv_airaccelerate.value : sv_accelerate.value;
1641 statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value >= 0 ? sv_wateraccelerate.value : sv_accelerate.value;
1642 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity);
1643 statsf[STAT_MOVEVARS_ENTGRAVITY] = (val && val->_float != 0) ? val->_float : 1.0f;
1644 statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value;
1645 statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
1646 statsf[STAT_MOVEVARS_MAXAIRSPEED] = sv_maxairspeed.value;
1647 statsf[STAT_MOVEVARS_STEPHEIGHT] = sv_stepheight.value;
1648 statsf[STAT_MOVEVARS_AIRACCEL_QW] = sv_airaccel_qw.value;
1649 statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value;
1650 statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value;
1651 statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value >= 0 ? sv_waterfriction.value : sv_friction.value;
1652 statsf[STAT_FRAGLIMIT] = fraglimit.value;
1653 statsf[STAT_TIMELIMIT] = timelimit.value;
1655 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)
1657 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1659 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1660 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1662 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1663 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1664 if (viewzoom != 255)
1665 bits |= SU_VIEWZOOM;
1670 if (bits >= 16777216)
1674 MSG_WriteByte (msg, svc_clientdata);
1675 MSG_WriteShort (msg, bits);
1676 if (bits & SU_EXTEND1)
1677 MSG_WriteByte(msg, bits >> 16);
1678 if (bits & SU_EXTEND2)
1679 MSG_WriteByte(msg, bits >> 24);
1681 if (bits & SU_VIEWHEIGHT)
1682 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1684 if (bits & SU_IDEALPITCH)
1685 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1687 for (i=0 ; i<3 ; i++)
1689 if (bits & (SU_PUNCH1<<i))
1691 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)
1692 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1694 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1696 if (bits & (SU_PUNCHVEC1<<i))
1698 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1699 MSG_WriteCoord16i(msg, punchvector[i]);
1701 MSG_WriteCoord32f(msg, punchvector[i]);
1703 if (bits & (SU_VELOCITY1<<i))
1705 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)
1706 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1708 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1712 if (bits & SU_ITEMS)
1713 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1715 if (sv.protocol == PROTOCOL_DARKPLACES5)
1717 if (bits & SU_WEAPONFRAME)
1718 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1719 if (bits & SU_ARMOR)
1720 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1721 if (bits & SU_WEAPON)
1722 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1723 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1724 MSG_WriteShort (msg, stats[STAT_AMMO]);
1725 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1726 MSG_WriteShort (msg, stats[STAT_NAILS]);
1727 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1728 MSG_WriteShort (msg, stats[STAT_CELLS]);
1729 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1730 if (bits & SU_VIEWZOOM)
1731 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1733 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)
1735 if (bits & SU_WEAPONFRAME)
1736 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1737 if (bits & SU_ARMOR)
1738 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1739 if (bits & SU_WEAPON)
1741 if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1742 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1744 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1746 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1747 MSG_WriteByte (msg, stats[STAT_AMMO]);
1748 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1749 MSG_WriteByte (msg, stats[STAT_NAILS]);
1750 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1751 MSG_WriteByte (msg, stats[STAT_CELLS]);
1752 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1754 for (i = 0;i < 32;i++)
1755 if (stats[STAT_ACTIVEWEAPON] & (1<<i))
1757 MSG_WriteByte (msg, i);
1760 MSG_WriteByte (msg, stats[STAT_ACTIVEWEAPON]);
1761 if (bits & SU_VIEWZOOM)
1763 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1764 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1766 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1771 void SV_FlushBroadcastMessages(void)
1775 if (sv.datagram.cursize <= 0)
1777 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1779 if (!client->spawned || !client->netconnection || client->unreliablemsg.cursize + sv.datagram.cursize > client->unreliablemsg.maxsize || client->unreliablemsg_splitpoints >= (int)(sizeof(client->unreliablemsg_splitpoint)/sizeof(client->unreliablemsg_splitpoint[0])))
1781 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
1782 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
1784 SZ_Clear(&sv.datagram);
1787 static void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg, int maxsize)
1789 // scan the splitpoints to find out how many we can fit in
1790 int numsegments, j, split;
1791 if (!client->unreliablemsg_splitpoints)
1793 // always accept the first one if it's within 1024 bytes, this ensures
1794 // that very big datagrams which are over the rate limit still get
1795 // through, just to keep it working
1796 j = msg->cursize + client->unreliablemsg_splitpoint[0];
1797 if (maxsize < 1024 && j > maxsize && j <= 1024)
1803 for (numsegments = 0;numsegments < client->unreliablemsg_splitpoints;numsegments++)
1804 if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > maxsize)
1806 if (numsegments > 0)
1808 // some will fit, so add the ones that will fit
1809 split = client->unreliablemsg_splitpoint[numsegments-1];
1810 // note this discards ones that were accepted by the segments scan but
1811 // can not fit, such as a really huge first one that will never ever
1812 // fit in a packet...
1813 if (msg->cursize + split <= maxsize)
1814 SZ_Write(msg, client->unreliablemsg.data, split);
1815 // remove the part we sent, keeping any remaining data
1816 client->unreliablemsg.cursize -= split;
1817 if (client->unreliablemsg.cursize > 0)
1818 memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
1819 // adjust remaining splitpoints
1820 client->unreliablemsg_splitpoints -= numsegments;
1821 for (j = 0;j < client->unreliablemsg_splitpoints;j++)
1822 client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
1827 =======================
1828 SV_SendClientDatagram
1829 =======================
1831 static void SV_SendClientDatagram (client_t *client)
1833 int clientrate, maxrate, maxsize, maxsize2, downloadsize;
1835 int stats[MAX_CL_STATS];
1836 unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE];
1838 // obey rate limit by limiting packet frequency if the packet size
1840 // (usually this is caused by reliable messages)
1841 if (!NetConn_CanSend(client->netconnection))
1844 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1845 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1846 if (sv_maxrate.integer != maxrate)
1847 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1849 // clientrate determines the 'cleartime' of a packet
1850 // (how long to wait before sending another, based on this packet's size)
1851 clientrate = bound(NET_MINRATE, client->rate, maxrate);
1853 switch (sv.protocol)
1855 case PROTOCOL_QUAKE:
1856 case PROTOCOL_QUAKEDP:
1857 case PROTOCOL_NEHAHRAMOVIE:
1858 case PROTOCOL_NEHAHRABJP:
1859 case PROTOCOL_NEHAHRABJP2:
1860 case PROTOCOL_NEHAHRABJP3:
1861 case PROTOCOL_QUAKEWORLD:
1862 // no packet size limit support on Quake protocols because it just
1863 // causes missing entities/effects
1864 // packets are simply sent less often to obey the rate limit
1868 case PROTOCOL_DARKPLACES1:
1869 case PROTOCOL_DARKPLACES2:
1870 case PROTOCOL_DARKPLACES3:
1871 case PROTOCOL_DARKPLACES4:
1872 // no packet size limit support on DP1-4 protocols because they kick
1873 // the client off if they overflow, and miss effects
1874 // packets are simply sent less often to obey the rate limit
1875 maxsize = sizeof(sv_sendclientdatagram_buf);
1876 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1879 // DP5 and later protocols support packet size limiting which is a
1880 // better method than limiting packet frequency as QW does
1882 // at very low rates (or very small sys_ticrate) the packet size is
1883 // not reduced below 128, but packets may be sent less often
1884 maxsize = (int)(clientrate * sys_ticrate.value);
1885 maxsize = bound(128, maxsize, 1400);
1887 // csqc entities can easily exceed 128 bytes, so disable throttling in
1888 // mods that use csqc (they are likely to use less bandwidth anyway)
1889 if (sv.csqc_progsize > 0)
1894 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1896 // for good singleplayer, send huge packets
1897 maxsize = sizeof(sv_sendclientdatagram_buf);
1898 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1899 // never limit frequency in singleplayer
1900 clientrate = 1000000000;
1903 // while downloading, limit entity updates to half the packet
1904 // (any leftover space will be used for downloading)
1905 if (host_client->download_file)
1908 msg.data = sv_sendclientdatagram_buf;
1909 msg.maxsize = sizeof(sv_sendclientdatagram_buf);
1911 msg.allowoverflow = false;
1913 if (host_client->spawned)
1915 // the player is in the game
1916 MSG_WriteByte (&msg, svc_time);
1917 MSG_WriteFloat (&msg, sv.time);
1919 // add the client specific data to the datagram
1920 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1921 // now update the stats[] array using any registered custom fields
1922 VM_SV_UpdateCustomStats (client, client->edict, &msg, stats);
1923 // set host_client->statsdeltabits
1924 Protocol_UpdateClientStats (stats);
1926 // add as many queued unreliable messages (effects) as we can fit
1927 // limit effects to half of the remaining space
1928 if (client->unreliablemsg.cursize)
1929 SV_WriteUnreliableMessages (client, &msg, (msg.cursize + maxsize) / 2);
1931 // now write as many entities as we can fit, and also sends stats
1932 SV_WriteEntitiesToClient (client, client->edict, &msg, maxsize);
1934 else if (realtime > client->keepalivetime)
1936 // the player isn't totally in the game yet
1937 // send small keepalive messages if too much time has passed
1938 // (may also be sending downloads)
1939 client->keepalivetime = realtime + 5;
1940 MSG_WriteChar (&msg, svc_nop);
1943 // if a download is active, see if there is room to fit some download data
1945 downloadsize = min(maxsize*2,maxsize2) - msg.cursize - 7;
1946 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1948 fs_offset_t downloadstart;
1949 unsigned char data[1400];
1950 downloadstart = FS_Tell(host_client->download_file);
1951 downloadsize = min(downloadsize, (int)sizeof(data));
1952 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1953 // note this sends empty messages if at the end of the file, which is
1954 // necessary to keep the packet loss logic working
1955 // (the last blocks may be lost and need to be re-sent, and that will
1956 // only occur if the client acks the empty end messages, revealing
1957 // a gap in the download progress, causing the last blocks to be
1959 MSG_WriteChar (&msg, svc_downloaddata);
1960 MSG_WriteLong (&msg, downloadstart);
1961 MSG_WriteShort (&msg, downloadsize);
1962 if (downloadsize > 0)
1963 SZ_Write (&msg, data, downloadsize);
1966 // reliable only if none is in progress
1967 if(client->sendsignon != 2 && !client->netconnection->sendMessageLength)
1968 SV_WriteDemoMessage(client, &(client->netconnection->message), false);
1970 SV_WriteDemoMessage(client, &msg, false);
1972 // send the datagram
1973 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate, client->sendsignon == 2);
1974 if (client->sendsignon == 1 && !client->netconnection->message.cursize)
1975 client->sendsignon = 2; // prevent reliable until client sends prespawn (this is the keepalive phase)
1979 =======================
1980 SV_UpdateToReliableMessages
1981 =======================
1983 static void SV_UpdateToReliableMessages (void)
1992 // check for changes to be sent over the reliable streams
1993 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1995 // update the host_client fields we care about according to the entity fields
1996 host_client->edict = PRVM_EDICT_NUM(i+1);
1999 name = PRVM_GetString(host_client->edict->fields.server->netname);
2002 // always point the string back at host_client->name to keep it safe
2003 strlcpy (host_client->name, name, sizeof (host_client->name));
2004 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
2005 if (strcmp(host_client->old_name, host_client->name))
2007 if (host_client->spawned)
2008 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
2009 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
2010 // send notification to all clients
2011 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
2012 MSG_WriteByte (&sv.reliable_datagram, i);
2013 MSG_WriteString (&sv.reliable_datagram, host_client->name);
2014 SV_WriteNetnameIntoDemo(host_client);
2017 // DP_SV_CLIENTCOLORS
2018 // this is always found (since it's added by the progs loader)
2019 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
2020 host_client->colors = (int)val->_float;
2021 if (host_client->old_colors != host_client->colors)
2023 host_client->old_colors = host_client->colors;
2024 // send notification to all clients
2025 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2026 MSG_WriteByte (&sv.reliable_datagram, i);
2027 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
2030 // NEXUIZ_PLAYERMODEL
2031 if( prog->fieldoffsets.playermodel >= 0 ) {
2032 model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
2035 // always point the string back at host_client->name to keep it safe
2036 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
2037 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
2040 // NEXUIZ_PLAYERSKIN
2041 if( prog->fieldoffsets.playerskin >= 0 ) {
2042 skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
2045 // always point the string back at host_client->name to keep it safe
2046 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
2047 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
2050 // TODO: add an extension name for this [1/17/2008 Black]
2051 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcamera)) && val->edict > 0 ) {
2052 int oldclientcamera = host_client->clientcamera;
2053 if( val->edict >= prog->max_edicts || PRVM_EDICT_NUM( val->edict )->priv.required->free ) {
2054 val->edict = host_client->clientcamera = PRVM_NUM_FOR_EDICT( host_client->edict );
2056 host_client->clientcamera = val->edict;
2059 if( oldclientcamera != host_client->clientcamera ) {
2060 MSG_WriteByte (&sv.reliable_datagram, svc_setview );
2061 MSG_WriteShort (&host_client->netconnection->message, host_client->clientcamera);
2066 host_client->frags = (int)host_client->edict->fields.server->frags;
2067 if(gamemode == GAME_NEXUIZ)
2068 if(!host_client->spawned && host_client->netconnection)
2069 host_client->frags = -666;
2070 if (host_client->old_frags != host_client->frags)
2072 host_client->old_frags = host_client->frags;
2073 // send notification to all clients
2074 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
2075 MSG_WriteByte (&sv.reliable_datagram, i);
2076 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
2080 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
2081 if (client->netconnection && (client->spawned || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet
2082 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
2084 SZ_Clear (&sv.reliable_datagram);
2089 =======================
2090 SV_SendClientMessages
2091 =======================
2093 void SV_SendClientMessages (void)
2095 int i, prepared = false;
2097 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2098 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
2100 SV_FlushBroadcastMessages();
2102 // update frags, names, etc
2103 SV_UpdateToReliableMessages();
2105 // build individual updates
2106 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2108 if (!host_client->active)
2110 if (!host_client->netconnection)
2113 if (host_client->netconnection->message.overflowed)
2115 SV_DropClient (true); // if the message couldn't send, kick off
2122 // only prepare entities once per frame
2123 SV_PrepareEntitiesForSending();
2125 SV_SendClientDatagram (host_client);
2128 // clear muzzle flashes
2132 static void SV_StartDownload_f(void)
2134 if (host_client->download_file)
2135 host_client->download_started = true;
2139 * Compression extension negotiation:
2142 * cl_serverextension_download 2
2145 * download <filename> <list of zero or more suppported compressions in order of preference>
2147 * download maps/map1.bsp lzo deflate huffman
2150 * cl_downloadbegin <compressed size> <filename> <compression method actually used>
2152 * cl_downloadbegin 123456 maps/map1.bsp deflate
2154 * The server may choose not to compress the file by sending no compression name, like:
2155 * cl_downloadbegin 345678 maps/map1.bsp
2157 * NOTE: the "download" command may only specify compression algorithms if
2158 * cl_serverextension_download is 2!
2159 * If cl_serverextension_download has a different value, the client must
2160 * assume this extension is not supported!
2163 static void Download_CheckExtensions(void)
2166 int argc = Cmd_Argc();
2168 // first reset them all
2169 host_client->download_deflate = false;
2171 for(i = 2; i < argc; ++i)
2173 if(!strcmp(Cmd_Argv(i), "deflate"))
2175 host_client->download_deflate = true;
2181 static void SV_Download_f(void)
2183 const char *whichpack, *whichpack2, *extension;
2184 qboolean is_csqc; // so we need to check only once
2188 SV_ClientPrintf("usage: download <filename> {<extensions>}*\n");
2189 SV_ClientPrintf(" supported extensions: deflate\n");
2193 if (FS_CheckNastyPath(Cmd_Argv(1), false))
2195 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
2199 if (host_client->download_file)
2201 // at this point we'll assume the previous download should be aborted
2202 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
2203 Host_ClientCommands("\nstopdownload\n");
2205 // close the file and reset variables
2206 FS_Close(host_client->download_file);
2207 host_client->download_file = NULL;
2208 host_client->download_name[0] = 0;
2209 host_client->download_expectedposition = 0;
2210 host_client->download_started = false;
2213 is_csqc = (sv.csqc_progname[0] && strcmp(Cmd_Argv(1), sv.csqc_progname) == 0);
2215 if (!sv_allowdownloads.integer && !is_csqc)
2217 SV_ClientPrintf("Downloads are disabled on this server\n");
2218 Host_ClientCommands("\nstopdownload\n");
2222 Download_CheckExtensions();
2224 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
2225 extension = FS_FileExtension(host_client->download_name);
2227 // host_client is asking to download a specified file
2228 if (developer.integer >= 100)
2229 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
2233 char extensions[MAX_QPATH]; // make sure this can hold all extensions
2234 extensions[0] = '\0';
2236 if(host_client->download_deflate)
2237 strlcat(extensions, " deflate", sizeof(extensions));
2239 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
2241 if(host_client->download_deflate)
2242 host_client->download_file = FS_FileFromData(svs.csqc_progdata_deflated, svs.csqc_progsize_deflated, true);
2244 host_client->download_file = FS_FileFromData(svs.csqc_progdata, sv.csqc_progsize, true);
2246 // no, no space is needed between %s and %s :P
2247 Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions);
2249 host_client->download_expectedposition = 0;
2250 host_client->download_started = false;
2251 host_client->sendsignon = true; // make sure this message is sent
2255 if (!FS_FileExists(host_client->download_name))
2257 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);
2258 Host_ClientCommands("\nstopdownload\n");
2262 // check if the user is trying to download part of registered Quake(r)
2263 whichpack = FS_WhichPack(host_client->download_name);
2264 whichpack2 = FS_WhichPack("gfx/pop.lmp");
2265 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
2267 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);
2268 Host_ClientCommands("\nstopdownload\n");
2272 // check if the server has forbidden archive downloads entirely
2273 if (!sv_allowdownloads_inarchive.integer)
2275 whichpack = FS_WhichPack(host_client->download_name);
2278 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);
2279 Host_ClientCommands("\nstopdownload\n");
2284 if (!sv_allowdownloads_config.integer)
2286 if (!strcasecmp(extension, "cfg"))
2288 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);
2289 Host_ClientCommands("\nstopdownload\n");
2294 if (!sv_allowdownloads_dlcache.integer)
2296 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
2298 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);
2299 Host_ClientCommands("\nstopdownload\n");
2304 if (!sv_allowdownloads_archive.integer)
2306 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
2308 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);
2309 Host_ClientCommands("\nstopdownload\n");
2314 host_client->download_file = FS_OpenVirtualFile(host_client->download_name, true);
2315 if (!host_client->download_file)
2317 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
2318 Host_ClientCommands("\nstopdownload\n");
2322 if (FS_FileSize(host_client->download_file) > 1<<30)
2324 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
2325 Host_ClientCommands("\nstopdownload\n");
2326 FS_Close(host_client->download_file);
2327 host_client->download_file = NULL;
2331 if (FS_FileSize(host_client->download_file) < 0)
2333 SV_ClientPrintf("Download rejected: file \"%s\" is not a regular file\n", host_client->download_name);
2334 Host_ClientCommands("\nstopdownload\n");
2335 FS_Close(host_client->download_file);
2336 host_client->download_file = NULL;
2340 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
2343 * we can only do this if we would actually deflate on the fly
2344 * which we do not (yet)!
2346 char extensions[MAX_QPATH]; // make sure this can hold all extensions
2347 extensions[0] = '\0';
2349 if(host_client->download_deflate)
2350 strlcat(extensions, " deflate", sizeof(extensions));
2352 // no, no space is needed between %s and %s :P
2353 Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions);
2356 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
2358 host_client->download_expectedposition = 0;
2359 host_client->download_started = false;
2360 host_client->sendsignon = true; // make sure this message is sent
2362 // the rest of the download process is handled in SV_SendClientDatagram
2363 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
2365 // no svc_downloaddata messages will be sent until sv_startdownload is
2366 // sent by the client
2370 ==============================================================================
2374 ==============================================================================
2383 int SV_ModelIndex(const char *s, int precachemode)
2385 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);
2386 char filename[MAX_QPATH];
2390 //if (precachemode == 2)
2392 strlcpy(filename, s, sizeof(filename));
2393 for (i = 2;i < limit;i++)
2395 if (!sv.model_precache[i][0])
2399 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))
2401 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
2404 if (precachemode == 1)
2405 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
2406 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
2407 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.modelname : NULL);
2408 if (sv.state != ss_loading)
2410 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
2411 MSG_WriteShort(&sv.reliable_datagram, i);
2412 MSG_WriteString(&sv.reliable_datagram, filename);
2416 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
2419 if (!strcmp(sv.model_precache[i], filename))
2422 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
2432 int SV_SoundIndex(const char *s, int precachemode)
2434 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);
2435 char filename[MAX_QPATH];
2439 //if (precachemode == 2)
2441 strlcpy(filename, s, sizeof(filename));
2442 for (i = 1;i < limit;i++)
2444 if (!sv.sound_precache[i][0])
2448 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))
2450 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
2453 if (precachemode == 1)
2454 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
2455 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
2456 if (sv.state != ss_loading)
2458 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
2459 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
2460 MSG_WriteString(&sv.reliable_datagram, filename);
2464 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
2467 if (!strcmp(sv.sound_precache[i], filename))
2470 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
2476 SV_ParticleEffectIndex
2480 int SV_ParticleEffectIndex(const char *name)
2482 int i, argc, linenumber, effectnameindex;
2483 fs_offset_t filesize;
2484 unsigned char *filedata;
2485 const char *text, *textstart, *textend;
2486 char argv[16][1024];
2487 if (!sv.particleeffectnamesloaded)
2489 sv.particleeffectnamesloaded = true;
2490 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
2491 for (i = 0;i < EFFECT_TOTAL;i++)
2492 strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
2493 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
2496 textstart = (const char *)filedata;
2497 textend = (const char *)filedata + filesize;
2499 for (linenumber = 1;;linenumber++)
2504 if (!COM_ParseToken_Simple(&text, true, false) || !strcmp(com_token, "\n"))
2508 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
2512 if (com_token[0] == 0)
2513 break; // if the loop exited and it's not a \n, it's EOF
2516 if (!strcmp(argv[0], "effect"))
2520 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
2522 if (sv.particleeffectname[effectnameindex][0])
2524 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
2529 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
2533 // if we run out of names, abort
2534 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
2536 Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
2545 // search for the name
2546 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
2547 if (!strcmp(sv.particleeffectname[effectnameindex], name))
2548 return effectnameindex;
2549 // return 0 if we couldn't find it
2559 static void SV_CreateBaseline (void)
2561 int i, entnum, large;
2562 prvm_edict_t *svent;
2564 // LordHavoc: clear *all* states (note just active ones)
2565 for (entnum = 0;entnum < prog->max_edicts;entnum++)
2567 // get the current server version
2568 svent = PRVM_EDICT_NUM(entnum);
2570 // LordHavoc: always clear state values, whether the entity is in use or not
2571 svent->priv.server->baseline = defaultstate;
2573 if (svent->priv.server->free)
2575 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
2578 // create entity baseline
2579 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
2580 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
2581 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
2582 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
2583 if (entnum > 0 && entnum <= svs.maxclients)
2585 svent->priv.server->baseline.colormap = entnum;
2586 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
2590 svent->priv.server->baseline.colormap = 0;
2591 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
2595 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
2598 if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
2602 // add to the message
2604 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
2606 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
2607 MSG_WriteShort (&sv.signon, entnum);
2611 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
2612 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
2614 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
2616 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
2617 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
2621 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
2622 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
2624 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
2625 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
2626 for (i=0 ; i<3 ; i++)
2628 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
2629 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
2638 Load csprogs.dat and comperss it so it doesn't need to be
2639 reloaded on request.
2642 void SV_Prepare_CSQC(void)
2644 fs_offset_t progsize;
2646 if(svs.csqc_progdata)
2648 Con_DPrintf("Unloading old CSQC data.\n");
2649 Mem_Free(svs.csqc_progdata);
2650 if(svs.csqc_progdata_deflated)
2651 Mem_Free(svs.csqc_progdata_deflated);
2654 svs.csqc_progdata = NULL;
2655 svs.csqc_progdata_deflated = NULL;
2657 Con_Print("Loading csprogs.dat\n");
2659 sv.csqc_progname[0] = 0;
2660 svs.csqc_progdata = FS_LoadFile(csqc_progname.string, sv_mempool, false, &progsize);
2664 size_t deflated_size;
2666 sv.csqc_progsize = (int)progsize;
2667 sv.csqc_progcrc = CRC_Block(svs.csqc_progdata, progsize);
2668 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2669 Con_Printf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2671 Con_Print("Compressing csprogs.dat\n");
2672 //unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflated_size, int level, mempool_t *mempool);
2673 svs.csqc_progdata_deflated = FS_Deflate(svs.csqc_progdata, progsize, &deflated_size, -1, sv_mempool);
2674 svs.csqc_progsize_deflated = (int)deflated_size;
2675 Con_Printf("Deflated: %g%%\n", 100.0 - 100.0 * (deflated_size / (float)progsize));
2676 Con_DPrintf("Uncompressed: %u\nCompressed: %u\n", (unsigned)sv.csqc_progsize, (unsigned)svs.csqc_progsize_deflated);
2684 Grabs the current state of each client for saving across the
2685 transition to another level
2688 void SV_SaveSpawnparms (void)
2692 svs.serverflags = (int)prog->globals.server->serverflags;
2694 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2696 if (!host_client->active)
2699 // call the progs to get default spawn parms for the new client
2700 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2701 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
2702 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
2703 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
2711 This is called at the start of each level
2715 void SV_SpawnServer (const char *server)
2720 dp_model_t *worldmodel;
2721 char modelname[sizeof(sv.modelname)];
2723 Con_DPrintf("SpawnServer: %s\n", server);
2725 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2727 if (!FS_FileExists(modelname))
2729 Con_Printf("SpawnServer: no map file named %s\n", modelname);
2733 if (cls.state != ca_dedicated)
2735 SCR_BeginLoadingPlaque();
2742 if(prog->funcoffsets.SV_Shutdown)
2744 func_t s = prog->funcoffsets.SV_Shutdown;
2745 prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
2746 PRVM_ExecuteProgram(s,"SV_Shutdown() required");
2751 // free q3 shaders so that any newly downloaded shaders will be active
2752 Mod_FreeQ3Shaders();
2754 worldmodel = Mod_ForName(modelname, false, true, NULL);
2755 if (!worldmodel || !worldmodel->TraceBox)
2757 Con_Printf("Couldn't load map %s\n", modelname);
2761 // let's not have any servers with no name
2762 if (hostname.string[0] == 0)
2763 Cvar_Set ("hostname", "UNNAMED");
2764 scr_centertime_off = 0;
2766 svs.changelevel_issued = false; // now safe to issue another
2768 // make the map a required file for clients
2769 Curl_ClearRequirements();
2770 Curl_RequireFile(modelname);
2773 // tell all connected clients that we are going to a new level
2778 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2780 if (client->netconnection)
2782 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2783 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2790 NetConn_OpenServerPorts(true);
2794 // make cvars consistant
2797 Cvar_SetValue ("deathmatch", 0);
2798 // LordHavoc: it can be useful to have skills outside the range 0-3...
2799 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2800 //Cvar_SetValue ("skill", (float)current_skill);
2801 current_skill = (int)(skill.value + 0.5);
2804 // set up the new server
2806 memset (&sv, 0, sizeof(sv));
2807 // if running a local client, make sure it doesn't try to access the last
2808 // level's data which is no longer valiud
2811 Cvar_SetValue("halflifebsp", worldmodel->brush.ishlbsp);
2813 if(*sv_random_seed.string)
2815 srand(sv_random_seed.integer);
2816 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);
2823 strlcpy (sv.name, server, sizeof (sv.name));
2825 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2826 if (sv.protocol == PROTOCOL_UNKNOWN)
2829 Protocol_Names(buffer, sizeof(buffer));
2830 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2831 sv.protocol = PROTOCOL_QUAKE;
2836 // load progs to get entity field count
2837 //PR_LoadProgs ( sv_progs.string );
2839 sv.datagram.maxsize = sizeof(sv.datagram_buf);
2840 sv.datagram.cursize = 0;
2841 sv.datagram.data = sv.datagram_buf;
2843 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2844 sv.reliable_datagram.cursize = 0;
2845 sv.reliable_datagram.data = sv.reliable_datagram_buf;
2847 sv.signon.maxsize = sizeof(sv.signon_buf);
2848 sv.signon.cursize = 0;
2849 sv.signon.data = sv.signon_buf;
2851 // leave slots at start for clients only
2852 //prog->num_edicts = svs.maxclients+1;
2854 sv.state = ss_loading;
2855 prog->allowworldwrites = true;
2858 prog->globals.server->time = sv.time = 1.0;
2861 worldmodel->used = true;
2863 strlcpy (sv.name, server, sizeof (sv.name));
2864 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2865 sv.worldmodel = worldmodel;
2866 sv.models[1] = sv.worldmodel;
2869 // clear world interaction links
2871 World_SetSize(&sv.world, sv.worldmodel->name, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs);
2873 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2875 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2876 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2877 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2879 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2880 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, sv.modelname);
2884 // load the rest of the entities
2886 // AK possible hack since num_edicts is still 0
2887 ent = PRVM_EDICT_NUM(0);
2888 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2889 ent->priv.server->free = false;
2890 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2891 ent->fields.server->modelindex = 1; // world model
2892 ent->fields.server->solid = SOLID_BSP;
2893 ent->fields.server->movetype = MOVETYPE_PUSH;
2894 VectorCopy(sv.world.mins, ent->fields.server->mins);
2895 VectorCopy(sv.world.maxs, ent->fields.server->maxs);
2896 VectorCopy(sv.world.mins, ent->fields.server->absmin);
2897 VectorCopy(sv.world.maxs, ent->fields.server->absmax);
2900 prog->globals.server->coop = coop.integer;
2902 prog->globals.server->deathmatch = deathmatch.integer;
2904 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2906 // serverflags are for cross level information (sigils)
2907 prog->globals.server->serverflags = svs.serverflags;
2909 // we need to reset the spawned flag on all connected clients here so that
2910 // their thinks don't run during startup (before PutClientInServer)
2911 // we also need to set up the client entities now
2912 // and we need to set the ->edict pointers to point into the progs edicts
2913 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2915 host_client->spawned = false;
2916 host_client->edict = PRVM_EDICT_NUM(i + 1);
2917 PRVM_ED_ClearEdict(host_client->edict);
2920 // load replacement entity file if found
2921 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2923 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2924 PRVM_ED_LoadFromFile (entities);
2928 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2931 // LordHavoc: clear world angles (to fix e3m3.bsp)
2932 VectorClear(prog->edicts->fields.server->angles);
2934 // all setup is completed, any further precache statements are errors
2935 // sv.state = ss_active; // LordHavoc: workaround for svc_precache bug
2936 prog->allowworldwrites = false;
2938 // run two frames to allow everything to settle
2939 prog->globals.server->time = sv.time = 1.0001;
2940 for (i = 0;i < 2;i++)
2946 if (cls.state == ca_dedicated)
2949 // create a baseline for more efficient communications
2950 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)
2951 SV_CreateBaseline ();
2953 sv.state = ss_active; // LordHavoc: workaround for svc_precache bug
2955 // to prevent network timeouts
2956 realtime = Sys_DoubleTime();
2958 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2959 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2961 host_client->clientconnectcalled = false; // do NOT call ClientDisconnect if he drops before ClientConnect!
2962 if (!host_client->active)
2964 if (host_client->netconnection)
2965 SV_SendServerinfo(host_client);
2969 // if client is a botclient coming from a level change, we need to
2970 // set up client info that normally requires networking
2972 // copy spawn parms out of the client_t
2973 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2974 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2976 // call the spawn function
2977 host_client->clientconnectcalled = true;
2978 prog->globals.server->time = sv.time;
2979 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2980 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2981 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2982 host_client->spawned = true;
2986 Con_DPrint("Server spawned.\n");
2987 NetConn_Heartbeat (2);
2992 /////////////////////////////////////////////////////
2995 static void SV_VM_CB_BeginIncreaseEdicts(void)
2997 // links don't survive the transition, so unlink everything
2998 World_UnlinkAll(&sv.world);
3001 static void SV_VM_CB_EndIncreaseEdicts(void)
3006 // link every entity except world
3007 for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
3008 if (!ent->priv.server->free)
3009 SV_LinkEdict(ent, false);
3012 static void SV_VM_CB_InitEdict(prvm_edict_t *e)
3014 // LordHavoc: for consistency set these here
3015 int num = PRVM_NUM_FOR_EDICT(e) - 1;
3017 e->priv.server->move = false; // don't move on first frame
3019 if (num >= 0 && num < svs.maxclients)
3022 // set colormap and team on newly created player entity
3023 e->fields.server->colormap = num + 1;
3024 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
3025 // set netname/clientcolors back to client values so that
3026 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
3028 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
3029 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
3030 val->_float = svs.clients[num].colors;
3031 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
3032 if( prog->fieldoffsets.playermodel >= 0 )
3033 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
3034 if( prog->fieldoffsets.playerskin >= 0 )
3035 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
3036 // Assign netaddress (IP Address, etc)
3037 if(prog->fieldoffsets.netaddress >= 0)
3038 { // Valid Field; Process
3039 if(svs.clients[num].netconnection != NULL)
3040 {// Valid Address; Assign
3041 // Acquire Readable Address
3042 LHNETADDRESS_ToString(&svs.clients[num].netconnection->peeraddress, svs.clients[num].netaddress, sizeof(svs.clients[num].netaddress), false);
3043 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString(svs.clients[num].netaddress);
3047 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString("null/botclient");
3052 static void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
3057 World_UnlinkEdict(ed); // unlink from world bsp
3059 ed->fields.server->model = 0;
3060 ed->fields.server->takedamage = 0;
3061 ed->fields.server->modelindex = 0;
3062 ed->fields.server->colormap = 0;
3063 ed->fields.server->skin = 0;
3064 ed->fields.server->frame = 0;
3065 VectorClear(ed->fields.server->origin);
3066 VectorClear(ed->fields.server->angles);
3067 ed->fields.server->nextthink = -1;
3068 ed->fields.server->solid = 0;
3070 // make sure csqc networking is aware of the removed entity
3071 e = PRVM_NUM_FOR_EDICT(ed);
3072 sv.csqcentityversion[e] = 0;
3073 for (i = 0;i < svs.maxclients;i++)
3075 if (svs.clients[i].csqcentityscope[e])
3076 svs.clients[i].csqcentityscope[e] = 1; // removed, awaiting send
3077 svs.clients[i].csqcentitysendflags[e] = 0xFFFFFF;
3081 static void SV_VM_CB_CountEdicts(void)
3085 int active, models, solid, step;
3087 active = models = solid = step = 0;
3088 for (i=0 ; i<prog->num_edicts ; i++)
3090 ent = PRVM_EDICT_NUM(i);
3091 if (ent->priv.server->free)
3094 if (ent->fields.server->solid)
3096 if (ent->fields.server->model)
3098 if (ent->fields.server->movetype == MOVETYPE_STEP)
3102 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
3103 Con_Printf("active :%3i\n", active);
3104 Con_Printf("view :%3i\n", models);
3105 Con_Printf("touch :%3i\n", solid);
3106 Con_Printf("step :%3i\n", step);
3109 static qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
3111 // remove things from different skill levels or deathmatch
3112 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
3114 if (deathmatch.integer)
3116 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
3121 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
3122 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
3123 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
3131 static void SV_VM_Setup(void)
3134 PRVM_InitProg( PRVM_SERVERPROG );
3136 // allocate the mempools
3137 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
3138 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
3139 prog->builtins = vm_sv_builtins;
3140 prog->numbuiltins = vm_sv_numbuiltins;
3141 prog->headercrc = PROGHEADER_CRC;
3142 prog->headercrc2 = PROGHEADER_CRC_TENEBRAE;
3143 prog->max_edicts = 512;
3144 if (sv.protocol == PROTOCOL_QUAKE)
3145 prog->limit_edicts = 640; // before quake mission pack 1 this was 512
3146 else if (sv.protocol == PROTOCOL_QUAKEDP)
3147 prog->limit_edicts = 2048; // guessing
3148 else if (sv.protocol == PROTOCOL_NEHAHRAMOVIE)
3149 prog->limit_edicts = 2048; // guessing!
3150 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
3151 prog->limit_edicts = 4096; // guessing!
3153 prog->limit_edicts = MAX_EDICTS;
3154 prog->reserved_edicts = svs.maxclients;
3155 prog->edictprivate_size = sizeof(edict_engineprivate_t);
3156 prog->name = "server";
3157 prog->extensionstring = vm_sv_extensions;
3158 prog->loadintoworld = true;
3160 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
3161 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
3162 prog->init_edict = SV_VM_CB_InitEdict;
3163 prog->free_edict = SV_VM_CB_FreeEdict;
3164 prog->count_edicts = SV_VM_CB_CountEdicts;
3165 prog->load_edict = SV_VM_CB_LoadEdict;
3166 prog->init_cmd = VM_SV_Cmd_Init;
3167 prog->reset_cmd = VM_SV_Cmd_Reset;
3168 prog->error_cmd = Host_Error;
3170 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
3171 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
3173 // some mods compiled with scrambling compilers lack certain critical
3174 // global names and field names such as "self" and "time" and "nextthink"
3175 // so we have to set these offsets manually, matching the entvars_t
3176 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
3177 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
3178 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
3179 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
3180 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
3181 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
3182 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
3183 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
3184 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
3185 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
3186 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
3187 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
3188 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
3189 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
3190 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
3191 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
3192 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
3193 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
3194 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
3195 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
3196 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
3197 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
3198 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
3199 // OP_STATE is always supported on server (due to entvars_t)
3200 prog->flag |= PRVM_OP_STATE;
3202 VM_CustomStats_Clear();//[515]: csqc
3209 void SV_VM_Begin(void)
3212 PRVM_SetProg( PRVM_SERVERPROG );
3214 prog->globals.server->time = (float) sv.time;
3217 void SV_VM_End(void)