00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "server.h"
00032
00033 void SV_Heartbeat_f (void)
00034 {
00035
00036 svs.lastHeartbeat = -9999999;
00037 }
00038
00043 void SV_SetMaster_f (void)
00044 {
00045 char *responseBuf;
00046
00047 if (sv_maxclients->integer == 1)
00048 return;
00049
00050
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
00064 SV_Heartbeat_f();
00065 }
00066
00072 static client_t* SV_GetPlayerClientStructure (const char *s)
00073 {
00074
00075 if (s[0] >= '0' && s[0] <= '9') {
00076 int idnum = atoi(Cmd_Argv(1));
00077 client_t *cl = NULL;
00078
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
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
00110 if (map[0] == '+') {
00111 Com_sprintf(expanded, sizeof(expanded), "maps/%s.ump", map + 1);
00112
00113
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
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
00171
00172 Q_strncpyz(bufMap, Cmd_Argv(2), sizeof(bufMap));
00173
00174 if (Cmd_Argc() == 4) {
00175 assembly = bufAssembly;
00176 Q_strncpyz(bufAssembly, Cmd_Argv(3), sizeof(bufAssembly));
00177 }
00178
00179
00180 if (!SV_CheckMap(bufMap, assembly))
00181 return;
00182
00183
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
00210
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
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
00414 partial = dayNightStr + 1;
00415 } else {
00416
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
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
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
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 }