sv_ccmds.c

Go to the documentation of this file.
00001 
00008 /*
00009 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00010 
00011 Original file from Quake 2 v3.21: quake2-2.31/server/sv_ccmds.c
00012 Copyright (C) 1997-2001 Id Software, Inc.
00013 
00014 This program is free software; you can redistribute it and/or
00015 modify it under the terms of the GNU General Public License
00016 as published by the Free Software Foundation; either version 2
00017 of the License, or (at your option) any later version.
00018 
00019 This program is distributed in the hope that it will be useful,
00020 but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 
00023 See the GNU General Public License for more details.
00024 
00025 You should have received a copy of the GNU General Public License
00026 along with this program; if not, write to the Free Software
00027 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00028 
00029 */
00030 
00031 #include "server.h"
00032 
00033 void SV_Heartbeat_f (void)
00034 {
00035     /* heartbeats will always be sent to the ufo master */
00036     svs.lastHeartbeat = -9999999;   /* send immediately */
00037 }
00038 
00043 void SV_SetMaster_f (void)
00044 {
00045     char *responseBuf;
00046 
00047     if (sv_maxclients->integer == 1)
00048         return;
00049 
00050     /* make sure the server is listed public */
00051     Cvar_Set("public", "1");
00052 
00053     Com_Printf("Master server at [%s] - sending a ping\n", masterserver_url->string);
00054     responseBuf = HTTP_GetURL(va("%s/ufo/masterserver.php?ping&port=%s", masterserver_url->string, port->string));
00055     if (responseBuf) {
00056         Com_DPrintf(DEBUG_SERVER, "response: %s\n", responseBuf);
00057         Mem_Free(responseBuf);
00058     }
00059 
00060     if (!sv_dedicated->integer)
00061         return;
00062 
00063     /* only dedicated servers are sending heartbeats */
00064     SV_Heartbeat_f();
00065 }
00066 
00072 static client_t* SV_GetPlayerClientStructure (const char *s)
00073 {
00074     /* numeric values are just slot numbers */
00075     if (s[0] >= '0' && s[0] <= '9') {
00076         int idnum = atoi(Cmd_Argv(1));
00077         client_t *cl = NULL;
00078         /* check for a name match */
00079         while ((cl = SV_GetNextClient(cl)) != NULL && idnum > 0)
00080             idnum--;
00081         if (cl->state == cs_free) {
00082             Com_Printf("Client %i is not active\n", idnum);
00083             return NULL;
00084         }
00085         return cl;
00086     } else {
00087         client_t *cl = NULL;
00088         /* check for a name match */
00089         while ((cl = SV_GetNextClient(cl)) != NULL) {
00090             if (cl->state == cs_free)
00091                 continue;
00092             if (!strcmp(cl->name, s)) {
00093                 return cl;
00094             }
00095         }
00096     }
00097 
00098     Com_Printf("Userid %s is not on the server\n", s);
00099     return NULL;
00100 }
00101 
00105 qboolean SV_CheckMap (const char *map, const char *assembly)
00106 {
00107     char expanded[MAX_QPATH];
00108 
00109     /* base attacks starts with . and random maps with + */
00110     if (map[0] == '+') {
00111         Com_sprintf(expanded, sizeof(expanded), "maps/%s.ump", map + 1);
00112 
00113         /* check for ump file */
00114         if (FS_CheckFile("%s", expanded) < 0) {
00115             Com_Printf("Can't find %s\n", expanded);
00116             return qfalse;
00117         }
00118     } else if (!assembly) {
00119         Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map);
00120 
00121         /* check for bsp file */
00122         if (FS_CheckFile("%s", expanded) < 0) {
00123             Com_Printf("Can't find %s\n", expanded);
00124             return qfalse;
00125         }
00126     }
00127     return qtrue;
00128 }
00129 
00135 static void SV_Map_f (void)
00136 {
00137     const char *assembly = NULL;
00138     char bufMap[MAX_TOKEN_CHARS * MAX_TILESTRINGS];
00139     char bufAssembly[MAX_TOKEN_CHARS * MAX_TILESTRINGS];
00140     qboolean day;
00141 
00142     if (Cmd_Argc() < 3) {
00143         Com_Printf("Usage: %s <day|night> <mapname> [<assembly>]\n", Cmd_Argv(0));
00144         Com_Printf("Use 'maplist' to get a list of all installed maps\n");
00145         return;
00146     }
00147 
00148     if (!strcmp(Cmd_Argv(0), "devmap")) {
00149         Com_Printf("deactivate ai - make sure to reset sv_ai after maptesting\n");
00150         Cvar_SetValue("sv_ai", 0);
00151         Cvar_SetValue("sv_cheats", 1);
00152         Cvar_SetValue("sv_send_edicts", 1);
00153         Cvar_SetValue("g_notus", 1);
00154         Cvar_SetValue("g_nospawn", 1);
00155     } else {
00156         Cvar_SetValue("sv_ai", 1);
00157         Cvar_SetValue("sv_send_edicts", 0);
00158         Cvar_SetValue("g_notus", 0);
00159         Cvar_SetValue("g_nospawn", 0);
00160     }
00161 
00162     if (!strcmp(Cmd_Argv(1), "day")) {
00163         day = qtrue;
00164     } else if (!strcmp(Cmd_Argv(1), "night")) {
00165         day = qfalse;
00166     } else {
00167         Com_Printf("Invalid lightmap parameter - use day or night\n");
00168         return;
00169     }
00170     /* we copy them to buffers because the command pointers might be invalid soon */
00171 
00172     Q_strncpyz(bufMap, Cmd_Argv(2), sizeof(bufMap));
00173     /* assembled maps uses position strings */
00174     if (Cmd_Argc() == 4) {
00175         assembly = bufAssembly;
00176         Q_strncpyz(bufAssembly, Cmd_Argv(3), sizeof(bufAssembly));
00177     }
00178 
00179     /* check to make sure the level exists */
00180     if (!SV_CheckMap(bufMap, assembly))
00181         return;
00182 
00183     /* start up the next map */
00184     SV_Map(day, bufMap, assembly);
00185 }
00186 
00190 static void SV_Kick_f (void)
00191 {
00192     client_t *cl;
00193 
00194     if (!svs.initialized) {
00195         Com_Printf("No server running.\n");
00196         return;
00197     }
00198 
00199     if (Cmd_Argc() != 2) {
00200         Com_Printf("Usage: %s <userid>\n", Cmd_Argv(0));
00201         return;
00202     }
00203 
00204     cl = SV_GetPlayerClientStructure(Cmd_Argv(1));
00205     if (cl == NULL)
00206         return;
00207 
00208     SV_BroadcastPrintf(PRINT_CONSOLE, "%s was kicked\n", cl->name);
00209     /* print directly, because the dropped client won't get the
00210      * SV_BroadcastPrintf message */
00211     SV_DropClient(cl, "You were kicked from the game\n");
00212 }
00213 
00218 static void SV_StartGame_f (void)
00219 {
00220     client_t* cl = NULL;
00221     while ((cl = SV_GetNextClient(cl)) != NULL)
00222         if (cl->state != cs_free)
00223             cl->player->isReady = qtrue;
00224 }
00225 
00230 static void SV_Status_f (void)
00231 {
00232     int i;
00233     client_t *cl;
00234     const char *s;
00235     char buf[256];
00236 
00237     if (!svs.clients) {
00238         Com_Printf("No server running.\n");
00239         return;
00240     }
00241     Com_Printf("map              : %s (%s)\n", sv.name, (SV_GetConfigStringInteger(CS_LIGHTMAP) ? "day" : "night"));
00242     Com_Printf("active team      : %i\n", svs.ge->ClientGetActiveTeam());
00243 
00244     Com_Printf("num status  name            address              \n");
00245     Com_Printf("--- ------- --------------- ---------------------\n");
00246 
00247     cl = NULL;
00248     i = 0;
00249     while ((cl = SV_GetNextClient(cl)) != NULL) {
00250         char        state_buf[16];
00251         char const* state;
00252 
00253         i++;
00254 
00255         if (cl->state == cs_free)
00256             continue;
00257 
00258         switch (cl->state) {
00259         case cs_connected:
00260             state = "CONNECT"; break;
00261         case cs_spawning:
00262             state = "SPAWNIN"; break;
00263         case cs_began:
00264             state = "BEGAN  "; break;
00265 
00266         default:
00267             sprintf(state_buf, "%7i", cl->state);
00268             state = state_buf;
00269             break;
00270         }
00271 
00272         s = NET_StreamPeerToName(cl->stream, buf, sizeof(buf), qfalse);
00273         Com_Printf("%3i %s %-15s %-21s\n", i, state, cl->name, s);
00274     }
00275     Com_Printf("\n");
00276 }
00277 
00278 #ifdef DEDICATED_ONLY
00279 
00282 static void SV_ConSay_f (void)
00283 {
00284     const char *p;
00285     char text[1024];
00286 
00287     if (Cmd_Argc() < 2)
00288         return;
00289 
00290     if (!Com_ServerState()) {
00291         Com_Printf("no server is running\n");
00292         return;
00293     }
00294 
00295     Q_strncpyz(text, "serverconsole: ", sizeof(text));
00296     p = Cmd_Args();
00297 
00298     if (*p == '"')
00299         p++;
00300 
00301     Q_strcat(text, p, sizeof(text));
00302     if (text[strlen(text)] == '"')
00303         text[strlen(text)] = 0;
00304     SV_BroadcastPrintf(PRINT_CHAT, "%s\n", text);
00305 }
00306 #endif
00307 
00311 static void SV_Serverinfo_f (void)
00312 {
00313     Com_Printf("Server info settings:\n");
00314     Info_Print(Cvar_Serverinfo());
00315 }
00316 
00317 
00322 static void SV_UserInfo_f (void)
00323 {
00324     client_t *cl;
00325 
00326     if (!svs.initialized) {
00327         Com_Printf("No server running.\n");
00328         return;
00329     }
00330 
00331     if (Cmd_Argc() != 2) {
00332         Com_Printf("Usage: %s <userid>\n", Cmd_Argv(0));
00333         return;
00334     }
00335 
00336     cl = SV_GetPlayerClientStructure(Cmd_Argv(1));
00337     if (cl == NULL)
00338         return;
00339 
00340     Com_Printf("userinfo\n");
00341     Com_Printf("--------\n");
00342     Info_Print(cl->userinfo);
00343 }
00344 
00348 static void SV_KillServer_f (void)
00349 {
00350     if (!svs.initialized)
00351         return;
00352     SV_Shutdown("Server was killed.", qfalse);
00353 }
00354 
00358 static void SV_ServerCommand_f (void)
00359 {
00360     if (!svs.ge) {
00361         Com_Printf("No game loaded.\n");
00362         return;
00363     }
00364 
00365     if (Cmd_Argc() < 2) {
00366         Com_Printf("Usage: %s <command> <parameter>\n", Cmd_Argv(0));
00367         return;
00368     }
00369 
00370     Com_DPrintf(DEBUG_SERVER, "Execute game command '%s'\n", Cmd_Args());
00371 
00372     SDL_mutexP(svs.serverMutex);
00373 
00374     svs.ge->ServerCommand();
00375 
00376     SDL_mutexV(svs.serverMutex);
00377 }
00378 
00379 /*=========================================================== */
00380 
00386 static int SV_CompleteMapCommand (const char *partial, const char **match)
00387 {
00388     int i, matches = 0;
00389     const char *localMatch[MAX_COMPLETE];
00390     size_t len;
00391     const char *dayNightStr = NULL;
00392     static char dayNightMatch[7];
00393 
00394     if (partial[0])
00395         dayNightStr = strstr(partial, " ");
00396     if (!dayNightStr) {
00397         if (partial[0] == 'd') {
00398             Q_strncpyz(dayNightMatch,"day ",sizeof(dayNightMatch));
00399             *match = dayNightMatch;
00400             return 1;
00401         } else if (partial[0] == 'n') {
00402             Q_strncpyz(dayNightMatch,"night ",sizeof(dayNightMatch));
00403             *match = dayNightMatch;
00404             return 1;
00405         }
00406         /* neither day or night, delete previous content and display options */
00407         Com_Printf("day\nnight\n");
00408         dayNightMatch[0] = '\0';
00409         *match = dayNightMatch;
00410         return 2;
00411     } else {
00412         if (!strcmp(partial,"day ") || !strcmp(partial,"night ")) {
00413             /* dayNightStr is correct, use it */
00414             partial = dayNightStr + 1;
00415         } else {
00416             /* neither day or night, delete previous content and display options */
00417             Com_Printf("day\nnight\n");
00418             dayNightMatch[0] = '\0';
00419             *match = dayNightMatch;
00420             return 2;
00421         }
00422     }
00423 
00424 
00425     FS_GetMaps(qfalse);
00426 
00427     len = strlen(partial);
00428     if (!len) {
00429         /* list them all if there was no parameter given */
00430         for (i = 0; i <= fs_numInstalledMaps; i++)
00431             Com_Printf("%s\n", fs_maps[i]);
00432         return fs_numInstalledMaps;
00433     }
00434 
00435     localMatch[matches] = NULL;
00436 
00437     /* search all matches and fill the localMatch array */
00438     for (i = 0; i <= fs_numInstalledMaps; i++)
00439         if (!strncmp(partial, fs_maps[i], len)) {
00440             Com_Printf("%s\n", fs_maps[i]);
00441             localMatch[matches++] = fs_maps[i];
00442             if (matches >= MAX_COMPLETE)
00443                 break;
00444         }
00445 
00446     return Cmd_GenericCompleteFunction(len, match, matches, localMatch);
00447 }
00448 
00453 static void SV_ListMaps_f (void)
00454 {
00455     int i;
00456 
00457     FS_GetMaps(qtrue);
00458 
00459     for (i = 0; i <= fs_numInstalledMaps; i++)
00460         Com_Printf("%s\n", fs_maps[i]);
00461     Com_Printf("-----\n %i installed maps\n+name means random map assembly", fs_numInstalledMaps + 1);
00462 }
00463 
00468 static const char *serverCommandList[] = {
00469     "startgame", "Force the gamestart - useful for multiplayer games",
00470     "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'",
00471     "removeip", "Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host",
00472     "listip", "Prints the current list of filters",
00473     "writeip", "Dumps ips to listip.cfg so it can be executed at a later date",
00474     "ai_add", "Used to add ai opponents to a game - but no civilians",
00475     "win", "Call the end game function with the given team",
00476 #ifdef DEBUG
00477     "debug_showall", "Debug function: Reveal all items to all sides",
00478     "debug_actorinvlist", "Debug function to show the whole inventory of all connected clients on the server",
00479 #endif
00480     NULL
00481 };
00482 
00487 static int SV_CompleteServerCommand (const char *partial, const char **match)
00488 {
00489     int i, matches = 0;
00490     const char *localMatch[MAX_COMPLETE];
00491     size_t len;
00492     int numServerCommands;
00493 
00494     len = strlen(partial);
00495     if (!len) {
00496         for (i = 0; ; i += 2) {
00497             if (!serverCommandList[i])
00498                 break;
00499             Com_Printf("[cmd] %s\n", serverCommandList[i]);
00500             if (*serverCommandList[i + 1])
00501                 Com_Printf(COLORED_GREEN "      %s\n", serverCommandList[i + 1]);
00502         }
00503         return i - 1;
00504     }
00505 
00506     for (i = 0, numServerCommands = 0; ; numServerCommands++, i += 2) {
00507         if (!serverCommandList[i])
00508             break;
00509     }
00510 
00511     localMatch[matches] = NULL;
00512 
00513     /* search all matches and fill the localMatch array */
00514     for (i = 0; i < numServerCommands; i++)
00515         if (!strncmp(partial, serverCommandList[i * 2], len)) {
00516             Com_Printf("[cmd] %s\n", serverCommandList[i * 2]);
00517             if (*serverCommandList[i * 2 + 1])
00518                 Com_Printf(COLORED_GREEN "      %s\n", serverCommandList[i * 2 + 1]);
00519             localMatch[matches++] = serverCommandList[i * 2];
00520             if (matches >= MAX_COMPLETE)
00521                 break;
00522         }
00523 
00524     return Cmd_GenericCompleteFunction(len, match, matches, localMatch);
00525 }
00526 
00530 static void SV_PrintConfigStrings_f (void)
00531 {
00532     int i;
00533 
00534     for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
00535         const char *configString = SV_GetConfigString(i);
00536         if (configString[0] == '\0')
00537             continue;
00538         Com_Printf("configstring[%3i]: %s\n", i, configString);
00539     }
00540 }
00541 
00542 #ifdef DEBUG
00543 
00544 #include "../common/routing.h"
00545 
00550 static void Grid_DumpWholeServerMap_f (void)
00551 {
00552     int i;
00553 
00554     for (i = 0; i < ACTOR_MAX_SIZE; i++)
00555         RT_DumpWholeMap(&sv.mapTiles, &sv.mapData.map[i]);
00556 }
00557 
00562 static void Grid_DumpServerRoutes_f (void)
00563 {
00564     ipos3_t wpMins, wpMaxs;
00565     VecToPos(sv.mapData.mapMin, wpMins);
00566     VecToPos(sv.mapData.mapMax, wpMaxs);
00567     RT_WriteCSVFiles(sv.mapData.map, "ufoaiserver", wpMins, wpMaxs);
00568 }
00569 #endif
00570 
00574 void SV_InitOperatorCommands (void)
00575 {
00576     Cmd_AddCommand("heartbeat", SV_Heartbeat_f, "Sends a heartbeat to the masterserver");
00577     Cmd_AddCommand("kick", SV_Kick_f, "Kick a user from the server");
00578     Cmd_AddCommand("startgame", SV_StartGame_f, "Forces a game start even if not all players are ready yet");
00579     Cmd_AddCommand("status", SV_Status_f, "Prints status of server and connected clients");
00580     Cmd_AddCommand("serverinfo", SV_Serverinfo_f, "Prints the serverinfo that is visible in the server browsers");
00581     Cmd_AddCommand("info", SV_UserInfo_f, "Prints the userinfo for a given userid");
00582 
00583     Cmd_AddCommand("map", SV_Map_f, "Quit client and load the new map");
00584     Cmd_AddParamCompleteFunction("map", SV_CompleteMapCommand);
00585     Cmd_AddCommand("devmap", SV_Map_f, "Quit client and load the new map - deactivate the ai");
00586     Cmd_AddParamCompleteFunction("devmap", SV_CompleteMapCommand);
00587     Cmd_AddCommand("maplist", SV_ListMaps_f, "List of all available maps");
00588 
00589     Cmd_AddCommand("setmaster", SV_SetMaster_f, "Send ping command to masterserver (see cvar masterserver_url)");
00590 
00591 #ifdef DEDICATED_ONLY
00592     Cmd_AddCommand("say", SV_ConSay_f, "Broadcasts server messages to all connected players");
00593 #endif
00594 
00595 #ifdef DEBUG
00596     Cmd_AddCommand("debug_sgrid", Grid_DumpWholeServerMap_f, "Shows the whole server side pathfinding grid of the current loaded map");
00597     Cmd_AddCommand("debug_sroute", Grid_DumpServerRoutes_f, "Shows the whole server side pathfinding grid of the current loaded map");
00598 #endif
00599 
00600     Cmd_AddCommand("killserver", SV_KillServer_f, "Shuts the server down - and disconnect all clients");
00601     Cmd_AddCommand("sv_configstrings", SV_PrintConfigStrings_f, "Prints the server config strings to game console");
00602 
00603     Cmd_AddCommand("sv", SV_ServerCommand_f, "Server command");
00604     Cmd_AddParamCompleteFunction("sv", SV_CompleteServerCommand);
00605 }

Generated by  doxygen 1.6.2