File: | server/sv_ccmds.cpp |
Location: | line 76, column 7 |
Description: | Access to field 'state' results in a dereference of a null pointer (loaded from variable 'cl') |
1 | /** | ||
2 | * @file | ||
3 | * @brief Console-only server commands. | ||
4 | * | ||
5 | * These commands can only be entered from stdin or by a remote operator datagram. | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | All original material Copyright (C) 2002-2011 UFO: Alien Invasion. | ||
10 | |||
11 | Original file from Quake 2 v3.21: quake2-2.31/server/sv_ccmds.c | ||
12 | Copyright (C) 1997-2001 Id Software, Inc. | ||
13 | |||
14 | This program is free software; you can redistribute it and/or | ||
15 | modify it under the terms of the GNU General Public License | ||
16 | as published by the Free Software Foundation; either version 2 | ||
17 | of the License, or (at your option) any later version. | ||
18 | |||
19 | This program is distributed in the hope that it will be useful, | ||
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
22 | |||
23 | See the GNU General Public License for more details. | ||
24 | |||
25 | You should have received a copy of the GNU General Public License | ||
26 | along with this program; if not, write to the Free Software | ||
27 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
28 | |||
29 | */ | ||
30 | |||
31 | #include "server.h" | ||
32 | #include "../common/http.h" | ||
33 | |||
34 | void SV_Heartbeat_f (void) | ||
35 | { | ||
36 | /* heartbeats will always be sent to the ufo master */ | ||
37 | svs.lastHeartbeat = -9999999; /* send immediately */ | ||
38 | } | ||
39 | |||
40 | /** | ||
41 | * @brief Add the server to the master server list so that others can see the server in the server list | ||
42 | * @sa SV_InitGame | ||
43 | */ | ||
44 | void SV_SetMaster_f (void) | ||
45 | { | ||
46 | if (sv_maxclients->integer == 1) | ||
47 | return; | ||
48 | |||
49 | /* make sure the server is listed public */ | ||
50 | Cvar_Set("public", "1"); | ||
51 | |||
52 | Com_Printf("Master server at [%s] - sending a ping\n", masterserver_url->string); | ||
53 | HTTP_GetURL(va("%s/ufo/masterserver.php?ping&port=%s", masterserver_url->string, port->string), NULL__null); | ||
54 | |||
55 | if (!sv_dedicated->integer) | ||
56 | return; | ||
57 | |||
58 | /* only dedicated servers are sending heartbeats */ | ||
59 | SV_Heartbeat_f(); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * @brief searches a player by id or name | ||
64 | * @param[in] s Either the numeric id of the player, or the player name | ||
65 | * @return the client structure | ||
66 | */ | ||
67 | static client_t* SV_GetPlayerClientStructure (const char *s) | ||
68 | { | ||
69 | /* numeric values are just slot numbers */ | ||
70 | if (s[0] >= '0' && s[0] <= '9') { | ||
| |||
71 | int idnum = atoi(Cmd_Argv(1)); | ||
72 | client_t *cl = NULL__null; | ||
73 | /* check for a name match */ | ||
74 | while ((cl = SV_GetNextClient(cl)) != NULL__null && idnum > 0) | ||
| |||
75 | idnum--; | ||
76 | if (cl->state == cs_free) { | ||
| |||
77 | Com_Printf("Client %i is not active\n", idnum); | ||
78 | return NULL__null; | ||
79 | } | ||
80 | return cl; | ||
81 | } else { | ||
82 | client_t *cl = NULL__null; | ||
83 | /* check for a name match */ | ||
84 | while ((cl = SV_GetNextClient(cl)) != NULL__null) { | ||
85 | if (cl->state == cs_free) | ||
86 | continue; | ||
87 | if (Q_streq(cl->name, s)(strcmp(cl->name, s) == 0)) { | ||
88 | return cl; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | |||
93 | Com_Printf("Userid %s is not on the server\n", s); | ||
94 | return NULL__null; | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * @brief Checks whether a map exists | ||
99 | */ | ||
100 | bool SV_CheckMap (const char *map, const char *assembly) | ||
101 | { | ||
102 | char expanded[MAX_QPATH64]; | ||
103 | |||
104 | /* base attacks starts with . and random maps with + */ | ||
105 | if (map[0] == '+') { | ||
106 | Com_sprintf(expanded, sizeof(expanded), "maps/%s.ump", map + 1); | ||
107 | |||
108 | /* check for ump file */ | ||
109 | if (FS_CheckFile("%s", expanded) < 0) { | ||
110 | Com_Printf("Can't find %s\n", expanded); | ||
111 | return false; | ||
112 | } | ||
113 | } else if (!assembly) { | ||
114 | Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map); | ||
115 | |||
116 | /* check for bsp file */ | ||
117 | if (FS_CheckFile("%s", expanded) < 0) { | ||
118 | Com_Printf("Can't find %s\n", expanded); | ||
119 | return false; | ||
120 | } | ||
121 | } | ||
122 | return true; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * @brief Goes directly to a given map | ||
127 | * @sa SV_InitGame | ||
128 | * @sa SV_SpawnServer | ||
129 | */ | ||
130 | static void SV_Map_f (void) | ||
131 | { | ||
132 | const char *assembly = NULL__null; | ||
133 | char bufMap[MAX_TOKEN_CHARS256 * MAX_TILESTRINGS25]; | ||
134 | char bufAssembly[MAX_TOKEN_CHARS256 * MAX_TILESTRINGS25]; | ||
135 | bool day; | ||
136 | |||
137 | if (Cmd_Argc() < 3) { | ||
138 | Com_Printf("Usage: %s <day|night> <mapname> [<assembly>]\n", Cmd_Argv(0)); | ||
139 | Com_Printf("Use 'maplist' to get a list of all installed maps\n"); | ||
140 | return; | ||
141 | } | ||
142 | |||
143 | if (Q_streq(Cmd_Argv(0), "devmap")(strcmp(Cmd_Argv(0), "devmap") == 0)) { | ||
144 | Com_Printf("deactivate ai - make sure to reset sv_ai after maptesting\n"); | ||
145 | Cvar_SetValue("sv_ai", 0); | ||
146 | Cvar_SetValue("sv_cheats", 1); | ||
147 | Cvar_SetValue("sv_send_edicts", 1); | ||
148 | Cvar_SetValue("g_notu", 1); | ||
149 | Cvar_SetValue("g_nospawn", 1); | ||
150 | } else { | ||
151 | Cvar_SetValue("sv_ai", 1); | ||
152 | Cvar_SetValue("sv_send_edicts", 0); | ||
153 | Cvar_SetValue("g_notu", 0); | ||
154 | Cvar_SetValue("g_nospawn", 0); | ||
155 | } | ||
156 | |||
157 | if (Q_streq(Cmd_Argv(1), "day")(strcmp(Cmd_Argv(1), "day") == 0)) { | ||
158 | day = true; | ||
159 | } else if (Q_streq(Cmd_Argv(1), "night")(strcmp(Cmd_Argv(1), "night") == 0)) { | ||
160 | day = false; | ||
161 | } else { | ||
162 | Com_Printf("Invalid lightmap parameter - use day or night\n"); | ||
163 | return; | ||
164 | } | ||
165 | /* we copy them to buffers because the command pointers might be invalid soon */ | ||
166 | |||
167 | Q_strncpyz(bufMap, Cmd_Argv(2), sizeof(bufMap))Q_strncpyzDebug( bufMap, Cmd_Argv(2), sizeof(bufMap), "src/server/sv_ccmds.cpp" , 167 ); | ||
168 | /* assembled maps uses position strings */ | ||
169 | if (Cmd_Argc() == 4) { | ||
170 | assembly = bufAssembly; | ||
171 | Q_strncpyz(bufAssembly, Cmd_Argv(3), sizeof(bufAssembly))Q_strncpyzDebug( bufAssembly, Cmd_Argv(3), sizeof(bufAssembly ), "src/server/sv_ccmds.cpp", 171 ); | ||
172 | } | ||
173 | |||
174 | /* check to make sure the level exists */ | ||
175 | if (!SV_CheckMap(bufMap, assembly)) | ||
176 | return; | ||
177 | |||
178 | /* start up the next map */ | ||
179 | SV_Map(day, bufMap, assembly); | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * @brief Kick a user off of the server | ||
184 | */ | ||
185 | static void SV_Kick_f (void) | ||
186 | { | ||
187 | client_t *cl; | ||
188 | |||
189 | if (!svs.initialized) { | ||
| |||
190 | Com_Printf("No server running.\n"); | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | if (Cmd_Argc() != 2) { | ||
| |||
195 | Com_Printf("Usage: %s <userid>\n", Cmd_Argv(0)); | ||
196 | return; | ||
197 | } | ||
198 | |||
199 | cl = SV_GetPlayerClientStructure(Cmd_Argv(1)); | ||
| |||
200 | if (cl == NULL__null) | ||
201 | return; | ||
202 | |||
203 | SV_BroadcastPrintf(PRINT_CONSOLE2, "%s was kicked\n", cl->name); | ||
204 | /* print directly, because the dropped client won't get the | ||
205 | * SV_BroadcastPrintf message */ | ||
206 | SV_DropClient(cl, "You were kicked from the game\n"); | ||
207 | } | ||
208 | |||
209 | /** | ||
210 | * @brief Forces a game start even if not all players are ready yet | ||
211 | * @sa SV_CheckGameStart | ||
212 | */ | ||
213 | static void SV_StartGame_f (void) | ||
214 | { | ||
215 | client_t* cl = NULL__null; | ||
216 | int cnt = 0; | ||
217 | while ((cl = SV_GetNextClient(cl)) != NULL__null) { | ||
218 | if (cl->state != cs_free) { | ||
219 | cl->player->isReady = true; | ||
220 | cnt++; | ||
221 | } | ||
222 | } | ||
223 | Cvar_ForceSet("sv_maxclients", va("%i", cnt)); | ||
224 | } | ||
225 | |||
226 | /** | ||
227 | * @brief Prints some server info to the game console - like connected players | ||
228 | * and current running map | ||
229 | */ | ||
230 | static void SV_Status_f (void) | ||
231 | { | ||
232 | int i; | ||
233 | client_t *cl; | ||
234 | const char *s; | ||
235 | char buf[256]; | ||
236 | |||
237 | if (!svs.clients) { | ||
238 | Com_Printf("No server running.\n"); | ||
239 | return; | ||
240 | } | ||
241 | Com_Printf("map : %s (%s)\n", sv->name, (SV_GetConfigStringInteger(CS_LIGHTMAP12) ? "day" : "night")); | ||
242 | Com_Printf("active team : %i\n", svs.ge->ClientGetActiveTeam()); | ||
243 | |||
244 | Com_Printf("num status name timeout ready address \n"); | ||
245 | Com_Printf("--- ------- --------------- -------------- ----- ---------------------\n"); | ||
246 | |||
247 | cl = NULL__null; | ||
248 | i = 0; | ||
249 | while ((cl = SV_GetNextClient(cl)) != NULL__null) { | ||
250 | char state_buf[16]; | ||
251 | char const* state; | ||
252 | |||
253 | i++; | ||
254 | |||
255 | if (cl->state == cs_free) | ||
256 | continue; | ||
257 | |||
258 | switch (cl->state) { | ||
259 | case cs_connected: | ||
260 | state = "CONNECT"; break; | ||
261 | case cs_spawning: | ||
262 | state = "SPAWNIN"; break; | ||
263 | case cs_began: | ||
264 | state = "BEGAN "; break; | ||
265 | case cs_spawned: | ||
266 | state = "SPAWNED"; break; | ||
267 | |||
268 | default: | ||
269 | sprintf(state_buf, "%7i", cl->state); | ||
270 | state = state_buf; | ||
271 | break; | ||
272 | } | ||
273 | |||
274 | s = NET_StreamPeerToName(cl->stream, buf, sizeof(buf), false); | ||
275 | Com_Printf("%3i %s %-15s %14i %-5s %-21s\n", i, state, cl->name, cl->lastmessage, | ||
276 | cl->player->isReady ? "true" : "false", s); | ||
277 | } | ||
278 | Com_Printf("\n"); | ||
279 | } | ||
280 | |||
281 | #ifdef DEDICATED_ONLY | ||
282 | /** | ||
283 | * @sa SV_BroadcastPrintf | ||
284 | */ | ||
285 | static void SV_ConSay_f (void) | ||
286 | { | ||
287 | const char *p; | ||
288 | char text[1024]; | ||
289 | |||
290 | if (Cmd_Argc() < 2) | ||
291 | return; | ||
292 | |||
293 | if (!Com_ServerState()) { | ||
294 | Com_Printf("no server is running\n"); | ||
295 | return; | ||
296 | } | ||
297 | |||
298 | Q_strncpyz(text, "serverconsole: ", sizeof(text))Q_strncpyzDebug( text, "serverconsole: ", sizeof(text), "src/server/sv_ccmds.cpp" , 298 ); | ||
299 | p = Cmd_Args(); | ||
300 | |||
301 | if (*p == '"') | ||
302 | p++; | ||
303 | |||
304 | Q_strcat(text, p, sizeof(text)); | ||
305 | if (text[strlen(text)] == '"') | ||
306 | text[strlen(text)] = 0; | ||
307 | SV_BroadcastPrintf(PRINT_CHAT0, "%s\n", text); | ||
308 | } | ||
309 | #endif | ||
310 | |||
311 | /** | ||
312 | * @brief Examine or change the serverinfo string | ||
313 | */ | ||
314 | static void SV_Serverinfo_f (void) | ||
315 | { | ||
316 | Com_Printf("Server info settings:\n"); | ||
317 | Info_Print(Cvar_Serverinfo()); | ||
318 | } | ||
319 | |||
320 | |||
321 | /** | ||
322 | * @brief Examine all a users info strings | ||
323 | * @sa CL_UserInfo_f | ||
324 | */ | ||
325 | static void SV_UserInfo_f (void) | ||
326 | { | ||
327 | client_t *cl; | ||
328 | |||
329 | if (!svs.initialized) { | ||
330 | Com_Printf("No server running.\n"); | ||
331 | return; | ||
332 | } | ||
333 | |||
334 | if (Cmd_Argc() != 2) { | ||
335 | Com_Printf("Usage: %s <userid>\n", Cmd_Argv(0)); | ||
336 | return; | ||
337 | } | ||
338 | |||
339 | cl = SV_GetPlayerClientStructure(Cmd_Argv(1)); | ||
340 | if (cl == NULL__null) | ||
341 | return; | ||
342 | |||
343 | Com_Printf("userinfo\n"); | ||
344 | Com_Printf("--------\n"); | ||
345 | Info_Print(cl->userinfo); | ||
346 | } | ||
347 | |||
348 | /** | ||
349 | * @brief Kick everyone off, possibly in preparation for a new game | ||
350 | */ | ||
351 | static void SV_KillServer_f (void) | ||
352 | { | ||
353 | if (!svs.initialized) | ||
354 | return; | ||
355 | SV_Shutdown("Server was killed.", false); | ||
356 | } | ||
357 | |||
358 | /** | ||
359 | * @brief Let the game dll handle a command | ||
360 | */ | ||
361 | static void SV_ServerCommand_f (void) | ||
362 | { | ||
363 | if (!svs.ge) { | ||
364 | Com_Printf("No game loaded.\n"); | ||
365 | return; | ||
366 | } | ||
367 | |||
368 | if (Cmd_Argc() < 2) { | ||
369 | Com_Printf("Usage: %s <command> <parameter>\n", Cmd_Argv(0)); | ||
370 | return; | ||
371 | } | ||
372 | |||
373 | Com_DPrintf(DEBUG_SERVER0x40, "Execute game command '%s'\n", Cmd_Args()); | ||
374 | |||
375 | TH_MutexLock(svs.serverMutex)_TH_MutexLock((svs.serverMutex), "src/server/sv_ccmds.cpp", 375 ); | ||
376 | |||
377 | svs.ge->ServerCommand(); | ||
378 | |||
379 | TH_MutexUnlock(svs.serverMutex)_TH_MutexUnlock((svs.serverMutex), "src/server/sv_ccmds.cpp", 379); | ||
380 | } | ||
381 | |||
382 | /*=========================================================== */ | ||
383 | |||
384 | /** | ||
385 | * @brief Autocomplete function for the map command | ||
386 | * @param[out] match The found entry of the list we are searching, in case of more than one entry their common suffix is returned. | ||
387 | * @sa Cmd_AddParamCompleteFunction | ||
388 | */ | ||
389 | static int SV_CompleteMapCommand (const char *partial, const char **match) | ||
390 | { | ||
391 | const char *dayNightStr = NULL__null; | ||
392 | static char dayNightMatch[7]; | ||
393 | |||
394 | if (partial[0]) | ||
395 | dayNightStr = strstr(partial, " "); | ||
396 | if (!dayNightStr) { | ||
397 | if (partial[0] == 'd') { | ||
398 | Q_strncpyz(dayNightMatch,"day ",sizeof(dayNightMatch))Q_strncpyzDebug( dayNightMatch, "day ", sizeof(dayNightMatch) , "src/server/sv_ccmds.cpp", 398 ); | ||
399 | *match = dayNightMatch; | ||
400 | return 1; | ||
401 | } else if (partial[0] == 'n') { | ||
402 | Q_strncpyz(dayNightMatch,"night ",sizeof(dayNightMatch))Q_strncpyzDebug( dayNightMatch, "night ", sizeof(dayNightMatch ), "src/server/sv_ccmds.cpp", 402 ); | ||
403 | *match = dayNightMatch; | ||
404 | return 1; | ||
405 | } | ||
406 | /* neither day or night, delete previous content and display options */ | ||
407 | Com_Printf("day\nnight\n"); | ||
408 | dayNightMatch[0] = '\0'; | ||
409 | *match = dayNightMatch; | ||
410 | return 2; | ||
411 | } else { | ||
412 | if (Q_streq(partial, "day ")(strcmp(partial, "day ") == 0) || Q_streq(partial, "night ")(strcmp(partial, "night ") == 0)) { | ||
413 | /* dayNightStr is correct, use it */ | ||
414 | partial = dayNightStr + 1; | ||
415 | } else { | ||
416 | /* neither day or night, delete previous content and display options */ | ||
417 | Com_Printf("day\nnight\n"); | ||
418 | dayNightMatch[0] = '\0'; | ||
419 | *match = dayNightMatch; | ||
420 | return 2; | ||
421 | } | ||
422 | } | ||
423 | |||
424 | FS_GetMaps(false); | ||
425 | |||
426 | int n = 0; | ||
427 | for (char* const* i = fs_maps, * const* const end = i + fs_numInstalledMaps; i != end; ++i) { | ||
428 | if (Cmd_GenericCompleteFunction(*i, partial, match)) { | ||
429 | Com_Printf("%s\n", *i); | ||
430 | ++n; | ||
431 | } | ||
432 | } | ||
433 | return n; | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * @brief List all valid maps | ||
438 | * @sa FS_GetMaps | ||
439 | */ | ||
440 | static void SV_ListMaps_f (void) | ||
441 | { | ||
442 | int i; | ||
443 | |||
444 | FS_GetMaps(true); | ||
445 | |||
446 | for (i = 0; i <= fs_numInstalledMaps; i++) | ||
447 | Com_Printf("%s\n", fs_maps[i]); | ||
448 | Com_Printf("-----\n %i installed maps\n+name means random map assembly\n", fs_numInstalledMaps + 1); | ||
449 | } | ||
450 | |||
451 | /** | ||
452 | * @brief List for SV_CompleteServerCommand | ||
453 | * @sa ServerCommand | ||
454 | */ | ||
455 | struct serverCommand_t { | ||
456 | char const* name; | ||
457 | char const* description; | ||
458 | }; | ||
459 | |||
460 | static serverCommand_t const serverCommandList[] = { | ||
461 | { "startgame", "Force the gamestart - useful for multiplayer games" }, | ||
462 | { "addip", "The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with 'addip 192.246.40'" }, | ||
463 | { "removeip", "Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host" }, | ||
464 | { "listip", "Prints the current list of filters" }, | ||
465 | { "writeip", "Dumps ips to listip.cfg so it can be executed at a later date" }, | ||
466 | { "ai_add", "Used to add ai opponents to a game - but no civilians" }, | ||
467 | { "win", "Call the end game function with the given team" }, | ||
468 | #ifdef DEBUG1 | ||
469 | { "debug_showall", "Debug function: Reveal all items to all sides" }, | ||
470 | { "debug_actorinvlist", "Debug function to show the whole inventory of all connected clients on the server" }, | ||
471 | #endif | ||
472 | { 0, 0 } | ||
473 | }; | ||
474 | |||
475 | /** | ||
476 | * @brief Autocomplete function for server commands | ||
477 | * @sa ServerCommand | ||
478 | */ | ||
479 | static int SV_CompleteServerCommand (const char *partial, const char **match) | ||
480 | { | ||
481 | int n = 0; | ||
482 | for (serverCommand_t const* i = serverCommandList; i->name; ++i) { | ||
483 | if (Cmd_GenericCompleteFunction(i->name, partial, match)) { | ||
484 | Com_Printf("[cmd] %s\n", i->name); | ||
485 | if (*i->description) | ||
486 | Com_Printf(S_COLOR_GREEN"^2" " %s\n", i->description); | ||
487 | ++n; | ||
488 | } | ||
489 | } | ||
490 | return n; | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * @sa CL_ShowConfigstrings_f | ||
495 | */ | ||
496 | static void SV_PrintConfigStrings_f (void) | ||
497 | { | ||
498 | int i; | ||
499 | |||
500 | for (i = 0; i < MAX_CONFIGSTRINGS(((((16 +25)+25)+256)+256)+(256*2)); i++) { | ||
501 | const char *configString; | ||
502 | /* CS_TILES and CS_POSITIONS can stretch over multiple configstrings, | ||
503 | * so don't send the middle parts again. */ | ||
504 | if (i > CS_TILES16 && i < CS_POSITIONS(16 +25)) | ||
505 | continue; | ||
506 | if (i > CS_POSITIONS(16 +25) && i < CS_MODELS((16 +25)+25)) | ||
507 | continue; | ||
508 | configString = SV_GetConfigString(i); | ||
509 | if (configString[0] == '\0') | ||
510 | continue; | ||
511 | Com_Printf("configstring[%3i]: %s\n", i, configString); | ||
512 | } | ||
513 | } | ||
514 | |||
515 | #ifdef DEBUG1 | ||
516 | /** @todo this does not belong here */ | ||
517 | #include "../common/routing.h" | ||
518 | |||
519 | /** | ||
520 | * @brief Dumps contents of the entire server map to console for inspection. | ||
521 | * @sa CL_InitLocal | ||
522 | */ | ||
523 | static void Grid_DumpWholeServerMap_f (void) | ||
524 | { | ||
525 | int i; | ||
526 | |||
527 | for (i = 0; i < ACTOR_MAX_SIZE(2); i++) | ||
528 | RT_DumpWholeMap(&sv->mapTiles, &sv->mapData.map[i]); | ||
529 | } | ||
530 | |||
531 | /** | ||
532 | * @brief Dumps contents of the entire server routing table to CSV file. | ||
533 | * @sa CL_InitLocal | ||
534 | */ | ||
535 | static void Grid_DumpServerRoutes_f (void) | ||
536 | { | ||
537 | ipos3_t wpMins, wpMaxs; | ||
538 | VecToPos(sv->mapData.mapMin, wpMins)( (wpMins)[0] = ((int)(sv->mapData.mapMin)[0] + 4096) / 32 , (wpMins)[1] = ((int)(sv->mapData.mapMin)[1] + 4096) / 32 , (wpMins)[2] = std::min((8 - 1), ((int)(sv->mapData.mapMin )[2] / 64)) ); | ||
539 | VecToPos(sv->mapData.mapMax, wpMaxs)( (wpMaxs)[0] = ((int)(sv->mapData.mapMax)[0] + 4096) / 32 , (wpMaxs)[1] = ((int)(sv->mapData.mapMax)[1] + 4096) / 32 , (wpMaxs)[2] = std::min((8 - 1), ((int)(sv->mapData.mapMax )[2] / 64)) ); | ||
540 | RT_WriteCSVFiles(sv->mapData.map, "ufoaiserver", wpMins, wpMaxs); | ||
541 | } | ||
542 | #endif | ||
543 | |||
544 | /** | ||
545 | * @sa SV_Init | ||
546 | */ | ||
547 | void SV_InitOperatorCommands (void) | ||
548 | { | ||
549 | Cmd_AddCommand("heartbeat", SV_Heartbeat_f, "Sends a heartbeat to the masterserver"); | ||
550 | Cmd_AddCommand("kick", SV_Kick_f, "Kick a user from the server"); | ||
551 | Cmd_AddCommand("startgame", SV_StartGame_f, "Forces a game start even if not all players are ready yet"); | ||
552 | Cmd_AddCommand("status", SV_Status_f, "Prints status of server and connected clients"); | ||
553 | Cmd_AddCommand("serverinfo", SV_Serverinfo_f, "Prints the serverinfo that is visible in the server browsers"); | ||
554 | Cmd_AddCommand("info", SV_UserInfo_f, "Prints the userinfo for a given userid"); | ||
555 | |||
556 | Cmd_AddCommand("map", SV_Map_f, "Quit client and load the new map"); | ||
557 | Cmd_AddParamCompleteFunction("map", SV_CompleteMapCommand); | ||
558 | Cmd_AddCommand("devmap", SV_Map_f, "Quit client and load the new map - deactivate the ai"); | ||
559 | Cmd_AddParamCompleteFunction("devmap", SV_CompleteMapCommand); | ||
560 | Cmd_AddCommand("maplist", SV_ListMaps_f, "List of all available maps"); | ||
561 | |||
562 | Cmd_AddCommand("setmaster", SV_SetMaster_f, "Send ping command to masterserver (see cvar masterserver_url)"); | ||
563 | |||
564 | #ifdef DEDICATED_ONLY | ||
565 | Cmd_AddCommand("say", SV_ConSay_f, "Broadcasts server messages to all connected players"); | ||
566 | #endif | ||
567 | |||
568 | #ifdef DEBUG1 | ||
569 | Cmd_AddCommand("debug_sgrid", Grid_DumpWholeServerMap_f, "Shows the whole server side pathfinding grid of the current loaded map"); | ||
570 | Cmd_AddCommand("debug_sroute", Grid_DumpServerRoutes_f, "Shows the whole server side pathfinding grid of the current loaded map"); | ||
571 | #endif | ||
572 | |||
573 | Cmd_AddCommand("killserver", SV_KillServer_f, "Shuts the server down - and disconnect all clients"); | ||
574 | Cmd_AddCommand("sv_configstrings", SV_PrintConfigStrings_f, "Prints the server config strings to game console"); | ||
575 | |||
576 | Cmd_AddCommand("sv", SV_ServerCommand_f, "Server command"); | ||
577 | Cmd_AddParamCompleteFunction("sv", SV_CompleteServerCommand); | ||
578 | } |